Files
outline/server/utils/passport.ts
Nan Yu 41e425756d chore: refactor domain parsing to be more general (#3448)
* change the api of domain parsing to just parseDomain and getCookieDomain
* adds getBaseDomain as the method to get the domain after any official subdomains
2022-05-31 18:48:23 -07:00

69 lines
1.7 KiB
TypeScript

import crypto from "crypto";
import { addMinutes, subMinutes } from "date-fns";
import type { Request } from "express";
import fetch from "fetch-with-proxy";
import {
StateStoreStoreCallback,
StateStoreVerifyCallback,
} from "passport-oauth2";
import { getCookieDomain } from "@shared/utils/domains";
import { OAuthStateMismatchError } from "../errors";
export class StateStore {
key = "state";
store = (ctx: Request, callback: StateStoreStoreCallback) => {
// Produce a random string as state
const state = crypto.randomBytes(8).toString("hex");
ctx.cookies.set(this.key, state, {
httpOnly: false,
expires: addMinutes(new Date(), 10),
domain: getCookieDomain(ctx.hostname),
});
callback(null, state);
};
verify = (
ctx: Request,
providedState: string,
callback: StateStoreVerifyCallback
) => {
const state = ctx.cookies.get(this.key);
if (!state) {
return callback(
OAuthStateMismatchError("State not return in OAuth flow"),
false,
state
);
}
ctx.cookies.set(this.key, "", {
httpOnly: false,
expires: subMinutes(new Date(), 1),
domain: getCookieDomain(ctx.hostname),
});
if (state !== providedState) {
return callback(OAuthStateMismatchError(), false, state);
}
// @ts-expect-error Type in library is wrong
callback(null, true, state);
};
}
export async function request(endpoint: string, accessToken: string) {
const response = await fetch(endpoint, {
method: "GET",
credentials: "same-origin",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
});
return response.json();
}