diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/History.ts | 23 | ||||
-rw-r--r-- | src/server/apis/google/GoogleApiServerUtils.ts | 93 |
2 files changed, 56 insertions, 60 deletions
diff --git a/src/client/util/History.ts b/src/client/util/History.ts index cf156014d..9728e3177 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -1,7 +1,6 @@ /* eslint-disable no-use-before-define */ /* eslint-disable no-empty */ /* eslint-disable no-param-reassign */ -import queryString from 'query-string'; import { Doc } from '../../fields/Doc'; import { OmitKeys, ClientUtils } from '../../ClientUtils'; import { DocServer } from '../DocServer'; @@ -79,7 +78,7 @@ export namespace HistoryUtil { // } // } - const parsers: { [type: string]: (pathname: string[], opts: queryString.ParsedQuery) => ParsedUrl | undefined } = {}; + const parsers: { [type: string]: (pathname: string[], opts: URLSearchParams) => ParsedUrl | undefined } = {}; const stringifiers: { [type: string]: (state: ParsedUrl) => string } = {}; type ParserValue = true | 'none' | 'json' | ((value: string) => string | null | (string | null)[]); @@ -88,7 +87,7 @@ export namespace HistoryUtil { [key: string]: ParserValue; }; - function addParser(type: string, requiredFields: Parser, optionalFields: Parser, customParser?: (pathname: string[], opts: queryString.ParsedQuery, current: ParsedUrl) => ParsedUrl | null | undefined) { + function addParser(type: string, requiredFields: Parser, optionalFields: Parser, customParser?: (pathname: string[], opts: URLSearchParams, current: ParsedUrl) => ParsedUrl | null | undefined) { function parseValue(parser: ParserValue, value: string | (string | null)[] | null | undefined) { if (value === undefined || value === null) { return value; @@ -105,21 +104,21 @@ export namespace HistoryUtil { parsers[type] = (pathname, opts) => { const current: DocUrl & { [key: string]: null | (string | null)[] | string } = { type: 'doc', docId: '' }; for (const required in requiredFields) { - if (!(required in opts)) { + if (!opts.has(required)) { return undefined; } const parser = requiredFields[required]; - const value = parseValue(parser, opts[required]); + const value = parseValue(parser, opts.get(required)); if (value !== null && value !== undefined) { current[required] = value; } } for (const opt in optionalFields) { - if (!(opt in opts)) { + if (!opts.has(opt)) { continue; } const parser = optionalFields[opt]; - const value = parseValue(parser, opts[opt]); + const value = parseValue(parser, opts.get(opt)); if (value !== undefined) { current[opt] = value; } @@ -145,12 +144,12 @@ export namespace HistoryUtil { path = customStringifier(state, path); } const queryObj = OmitKeys(state, keys).extract; - const query: { [key: string]: string | null } = {}; + const query = new URLSearchParams(); Object.keys(queryObj).forEach(key => { - query[key] = queryObj[key] === null ? null : JSON.stringify(queryObj[key]); + query.set(key, queryObj[key] === null ? '' : JSON.stringify(queryObj[key])); }); - const qstr = queryString.stringify(query); - return path + (queryString ? `?${qstr}` : ''); + const qstr = query.toString(); + return path + (qstr ? `?${qstr}` : ''); }; } @@ -167,7 +166,7 @@ export namespace HistoryUtil { export function parseUrl(location: Location | URL): ParsedUrl | undefined { const pathname = location.pathname.substring(1); const { search } = location; - const opts = search.length ? queryString.parse(search, { sort: false }) : {}; + const opts = new URLSearchParams(search); const pathnameSplit = pathname.split('/'); const type = pathnameSplit[0]; diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 21c405bee..7373df473 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -1,7 +1,7 @@ +/* eslint-disable no-use-before-define */ import { GaxiosResponse } from 'gaxios'; import { Credentials, OAuth2Client, OAuth2ClientOptions } from 'google-auth-library'; import { google } from 'googleapis'; -import * as qs from 'query-string'; import * as request from 'request-promise'; import { Opt } from '../../../fields/Doc'; import { Database } from '../../database'; @@ -21,7 +21,6 @@ const scope = ['documents.readonly', 'documents', 'presentations', 'presentation * This namespace manages server side authentication for Google API queries, either * from the standard v1 APIs or the Google Photos REST API. */ - export namespace GoogleApiServerUtils { /** * As we expand out to more Google APIs that are accessible from @@ -71,29 +70,29 @@ export namespace GoogleApiServerUtils { /** * A briefer format for the response from a 'googleapis' API request */ - export type ApiResponse = Promise<GaxiosResponse>; + export type ApiResponse = Promise<GaxiosResponse<unknown>>; /** * A generic form for a handler that executes some request on the endpoint */ - export type ApiRouter = (endpoint: Endpoint, parameters: any) => ApiResponse; + export type ApiRouter = (endpoint: Endpoint, parameters: Record<string, unknown>) => ApiResponse; /** * A generic form for the asynchronous function that actually submits the - * request to the API and returns the corresporing response. Helpful when + * request to the API and returns the corresponding response. Helpful when * making an extensible endpoint definition. */ - export type ApiHandler = (parameters: any, methodOptions?: any) => ApiResponse; + export type ApiHandler = (parameters: Record<string, unknown>, methodOptions?: Record<string, unknown>) => ApiResponse; /** * A literal union type indicating the valid actions for these 'googleapis' - * requestions + * requests */ export type Action = 'create' | 'retrieve' | 'update'; /** * An interface defining any entity on which one can invoke - * anuy of the following handlers. All 'googleapis' wrappers + * any of the following handlers. All 'googleapis' wrappers * such as google.docs().documents and google.slides().presentations * satisfy this interface. */ @@ -109,7 +108,7 @@ export namespace GoogleApiServerUtils { * of needless duplicate clients that would arise from * making one new client instance per request. */ - const authenticationClients = new Map<String, OAuth2Client>(); + const authenticationClients = new Map<string, OAuth2Client>(); /** * This function receives the target sector ("which G-Suite app's API am I interested in?") @@ -120,23 +119,21 @@ export namespace GoogleApiServerUtils { * @returns the relevant 'googleapis' wrapper, if any */ export async function GetEndpoint(sector: string, userId: string): Promise<Endpoint | void> { - return new Promise(async resolve => { - const auth = await retrieveOAuthClient(userId); - if (!auth) { - return resolve(); - } - let routed: Opt<Endpoint>; - const parameters: any = { auth, version: 'v1' }; - switch (sector) { - case Service.Documents: - routed = google.docs(parameters).documents; - break; - case Service.Slides: - routed = google.slides(parameters).presentations; - break; - } - resolve(routed); - }); + const auth = await retrieveOAuthClient(userId); + if (!auth) { + return; + } + let routed: Opt<Endpoint>; + const parameters: { version: 'v1' } = { /* auth, */ version: 'v1' }; ///* auth: OAuth2Client;*/ + switch (sector) { + case Service.Documents: + routed = google.docs(parameters).documents; + break; + case Service.Slides: + routed = google.slides(parameters).presentations; + break; + } + return routed; } /** @@ -149,19 +146,17 @@ export namespace GoogleApiServerUtils { * security. */ export async function retrieveOAuthClient(userId: string): Promise<OAuth2Client | void> { - return new Promise(async resolve => { - const { credentials, refreshed } = await retrieveCredentials(userId); - if (!credentials) { - return resolve(); - } - let client = authenticationClients.get(userId); - if (!client) { - authenticationClients.set(userId, (client = generateClient(credentials))); - } else if (refreshed) { - client.setCredentials(credentials); - } - resolve(client); - }); + const { credentials, refreshed } = await retrieveCredentials(userId); + if (!credentials) { + return; + } + let client = authenticationClients.get(userId); + if (!client) { + authenticationClients.set(userId, (client = generateClient(credentials))); + } else if (refreshed) { + client.setCredentials(credentials); + } + return client; } /** @@ -173,7 +168,9 @@ export namespace GoogleApiServerUtils { */ function generateClient(credentials?: Credentials): OAuth2Client { const client = new google.auth.OAuth2(oAuthOptions); - credentials && client.setCredentials(credentials); + if (credentials) { + client.setCredentials(credentials); + } return client; } @@ -206,7 +203,7 @@ export namespace GoogleApiServerUtils { */ export async function processNewUser(userId: string, authenticationCode: string): Promise<EnrichedCredentials> { const credentials = await new Promise<Credentials>((resolve, reject) => { - worker.getToken(authenticationCode, async (err, credentials) => { + worker.getToken(authenticationCode, (err, credentials) => { if (err || !credentials) { reject(err); return; @@ -221,7 +218,7 @@ export namespace GoogleApiServerUtils { /** * This type represents the union of the full set of OAuth2 credentials - * and all of a Google user's publically available information. This is the strucure + * and all of a Google user's publicly available information. This is the structure * of the JSON object we ultimately store in the googleAuthentication table of the database. */ export type EnrichedCredentials = Credentials & { userInfo: UserInfo }; @@ -297,15 +294,15 @@ export namespace GoogleApiServerUtils { async function refreshAccessToken(credentials: Credentials, userId: string): Promise<Credentials> { const headerParameters = { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }; const { client_id, client_secret } = GoogleCredentialsLoader.ProjectCredentials; - const url = `https://oauth2.googleapis.com/token?${qs.stringify({ - refreshToken: credentials.refresh_token, + const params = new URLSearchParams({ + refresh_token: credentials.refresh_token!, client_id, client_secret, grant_type: 'refresh_token', - })}`; - const { access_token, expires_in } = await new Promise<any>(async resolve => { - const response = await request.post(url, headerParameters); - resolve(JSON.parse(response)); + }); + const url = `https://oauth2.googleapis.com/token?${params.toString()}`; + const { access_token, expires_in } = await new Promise<{ access_token: string; expires_in: number }>(resolve => { + request.post(url, headerParameters).then(response => resolve(JSON.parse(response))); }); // expires_in is in seconds, but we're building the new expiry date in milliseconds const expiry_date = new Date().getTime() + expires_in * 1000; |