(core) Google auth endpoint has not responded with auth code

Summary:
Google Auth popup wasn't able to resolve origin from gristConfig.
Moving this reponsability to server side, where it gets calculated from initial request.

Test Plan: n/a

Reviewers: dsagal, paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D2935
This commit is contained in:
Jarosław Sadziński 2021-07-21 18:38:57 +02:00
parent 08295a696b
commit 291bcd17ff
5 changed files with 20 additions and 18 deletions

View File

@ -11,7 +11,7 @@ export async function makeXLSX(
activeDoc: ActiveDoc,
req: express.Request): Promise<ArrayBuffer> {
const content = await exportDoc(activeDoc, req);
const data = await convertToExcel(content, req.host === 'localhost');
const data = await convertToExcel(content, req.hostname === 'localhost');
return data;
}

View File

@ -1232,7 +1232,7 @@ export class FlexServer implements GristServer {
public addGoogleAuthEndpoint() {
if (this._check('google-auth')) { return; }
const messagePage = makeMessagePage(this, getAppPathTo(this.appRoot, 'static'));
const messagePage = makeMessagePage(getAppPathTo(this.appRoot, 'static'));
addGoogleAuthEndpoint(this.app, messagePage);
}

View File

@ -130,15 +130,18 @@ export function addGoogleAuthEndpoint(
log.info(`GoogleAuth - auth handler at ${getFullAuthEndpointUrl()}`);
expressApp.get(authHandlerPath, expressWrap(async (req: express.Request, res: express.Response) => {
// Test if the code is in a query string. Google sends it back after user has given a concent for
// our request. It is encrypted (with CLIENT_SECRET) and signed with redirect url.
// In state query parameter we will receive an url that was send as part of the request to Google.
if (req.query.code) {
log.debug("GoogleAuth - response from Google with valid code");
messagePage(req, res, { code: req.query.code });
messagePage(req, res, { code: req.query.code, origin: req.query.state });
} else if (req.query.error) {
log.debug("GoogleAuth - response from Google with error code", req.query.error);
if (req.query.error === "access_denied") {
messagePage(req, res, { error: req.query.error });
messagePage(req, res, { error: req.query.error, origin: req.query.state });
} else {
// This should not happen, either code or error is a mandatory query parameter.
throw new ApiError("Error authenticating with Google", 500);
@ -146,13 +149,17 @@ export function addGoogleAuthEndpoint(
} else {
const oAuth2Client = _googleAuthClient();
const scope = req.query.scope || DRIVE_SCOPE;
// Create url for origin parameter for a popup window.
const origin = `${req.protocol}://${req.headers.host}`;
const authUrl = oAuth2Client.generateAuthUrl({
scope,
prompt: 'select_account'
prompt: 'select_account',
state: origin
});
log.debug(`GoogleAuth - redirecting to Google consent screen`, {
authUrl,
scope
scope,
state: origin
});
res.redirect(authUrl);
}

View File

@ -51,12 +51,10 @@ export function makeGristConfig(homeUrl: string|null, extra: Partial<GristLoadCo
* Primary used for Google Auth Grist's endpoint, but can be used in future in any other server side
* authentication flow.
*/
export function makeMessagePage(server: GristServer, staticDir: string) {
export function makeMessagePage(staticDir: string) {
return async (req: express.Request, resp: express.Response, message: any) => {
const config = server.getGristConfig();
const fileContent = await fse.readFile(path.join(staticDir, "message.html"), 'utf8');
const content = fileContent
.replace("<!-- INSERT CONFIG -->", `<script>window.gristConfig = ${JSON.stringify(config)};</script>`)
.replace("<!-- INSERT MESSAGE -->", `<script>window.message = ${JSON.stringify(message)};</script>`);
resp.status(200).type('html').send(content);
};

View File

@ -4,12 +4,9 @@
<meta charset="utf8">
</head>
<body>
<!-- INSERT CONFIG -->
<!-- INSERT MESSAGE -->
<script>
// Determine proper home url for origin parameter
const origin = gristConfig.pathOnly ? gristConfig.homeUrl : `https://${gristConfig.org}${gristConfig.baseDomain}`;
window.opener.postMessage(message, origin);
window.opener.postMessage(message, message.origin);
</script>
</body>
</html>