diff options
author | Sam Wilkins <samwilkins333@gmail.com> | 2019-10-12 19:13:25 -0400 |
---|---|---|
committer | Sam Wilkins <samwilkins333@gmail.com> | 2019-10-12 19:13:25 -0400 |
commit | 5b83d8da6c262897dc75ada26f08ed1c46ceb95c (patch) | |
tree | a9770d9b9b3520712f12fb099a99b32cad8f14d0 /src/server | |
parent | d7653cab93309717488d51c68c8b1f0db64b949c (diff) |
parse google user data and use it to provide customized feedback on login
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/apis/google/GoogleApiServerUtils.ts | 51 | ||||
-rw-r--r-- | src/server/database.ts | 5 | ||||
-rw-r--r-- | src/server/index.ts | 3 |
3 files changed, 50 insertions, 9 deletions
diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 963c7736a..5714c9928 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -25,7 +25,8 @@ export namespace GoogleApiServerUtils { 'drive.file', 'photoslibrary', 'photoslibrary.appendonly', - 'photoslibrary.sharing' + 'photoslibrary.sharing', + 'userinfo.profile' ]; export const parseBuffer = (data: Buffer) => JSON.parse(data.toString()); @@ -96,21 +97,61 @@ export namespace GoogleApiServerUtils { }); }; - export const ProcessClientSideCode = async (information: CredentialInformation, authenticationCode: string): Promise<TokenResult> => { + export interface GoogleAuthenticationResult { + access_token: string; + avatar: string; + name: string; + } + export const ProcessClientSideCode = async (information: CredentialInformation, authenticationCode: string): Promise<GoogleAuthenticationResult> => { const oAuth2Client = await RetrieveOAuthClient(information); - return new Promise<TokenResult>((resolve, reject) => { + return new Promise<GoogleAuthenticationResult>((resolve, reject) => { oAuth2Client.getToken(authenticationCode, async (err, token) => { if (err || !token) { reject(err); return console.error('Error retrieving access token', err); } oAuth2Client.setCredentials(token); - await Database.Auxiliary.GoogleAuthenticationToken.Write(information.userId, token); - resolve({ token, client: oAuth2Client }); + const enriched = injectUserInfo(token); + await Database.Auxiliary.GoogleAuthenticationToken.Write(information.userId, enriched); + const { given_name, picture } = enriched.userInfo; + resolve({ + access_token: enriched.access_token!, + avatar: picture, + name: given_name + }); }); }); }; + /** + * It's pretty cool: the credentials id_token is split into thirds by periods. + * The middle third contains a base64-encoded JSON string with all the + * user info contained in the interface below. So, we isolate that middle third, + * base64 decode with atob and parse the JSON. + * @param credentials the client credentials returned from OAuth after the user + * has executed the authentication routine + */ + const injectUserInfo = (credentials: Credentials): EnrichedCredentials => { + const userInfo = JSON.parse(atob(credentials.id_token!.split(".")[1])); + return { ...credentials, userInfo }; + }; + + export type EnrichedCredentials = Credentials & { userInfo: UserInfo }; + export interface UserInfo { + at_hash: string; + aud: string; + azp: string; + exp: number; + family_name: string; + given_name: string; + iat: number; + iss: string; + locale: string; + name: string; + picture: string; + sub: string; + } + export const RetrieveCredentials = (information: CredentialInformation) => { return new Promise<TokenResult>((resolve, reject) => { readFile(information.credentialsPath, async (err, credentials) => { diff --git a/src/server/database.ts b/src/server/database.ts index 990441d5a..db86b472d 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -4,6 +4,7 @@ import { Opt } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { DashUploadUtils } from './DashUploadUtils'; import { Credentials } from 'google-auth-library'; +import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils'; export namespace Database { @@ -259,8 +260,8 @@ export namespace Database { return SanitizedSingletonQuery<StoredCredentials>({ userId }, GoogleAuthentication, removeId); }; - export const Write = async (userId: string, token: any) => { - return Instance.insert({ userId, canAccess: [], ...token }, GoogleAuthentication); + export const Write = async (userId: string, enrichedCredentials: GoogleApiServerUtils.EnrichedCredentials) => { + return Instance.insert({ userId, canAccess: [], ...enrichedCredentials }, GoogleAuthentication); }; export const Update = async (userId: string, access_token: string, expiry_date: number) => { diff --git a/src/server/index.ts b/src/server/index.ts index 86c226a21..010a851bc 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -958,8 +958,7 @@ app.get(RouteStore.readGoogleAccessToken, async (req, res) => { app.post(RouteStore.writeGoogleAccessToken, async (req, res) => { const userId = req.header("userId")!; const information = { credentialsPath, userId }; - const { token } = await GoogleApiServerUtils.ProcessClientSideCode(information, req.body.authenticationCode); - res.send(token.access_token); + res.send(await GoogleApiServerUtils.ProcessClientSideCode(information, req.body.authenticationCode)); }); const tokenError = "Unable to successfully upload bytes for all images!"; |