diff --git a/Authentication/src/lib/Resolvable.ts b/Authentication/src/lib/Resolvable.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e313aae8b046e15f83dfd2198ab072573688c42 --- /dev/null +++ b/Authentication/src/lib/Resolvable.ts @@ -0,0 +1,26 @@ +export interface IResolvable<reply> extends Promise<reply> { + resolved: boolean; + resolve(msg: reply): void; + reject(msg: Error): void; +} + +export default function Resolvable<reply = void>(): IResolvable<reply> { + let resolver: (msg: any) => void; + let rejector: (msg: Error) => void; + + const promise: any = new Promise((res, rej) => { + resolver = res; + rejector = rej; + }); + + promise.resolved = false; + promise.resolve = (msg: any) => { + resolver(msg); + promise.resolved = true; + }; + promise.reject = (msg: Error) => { + rejector(msg); + promise.resolved = true; + }; + return promise; +} diff --git a/Authentication/src/providers/Canvas/refreshToken.ts b/Authentication/src/providers/Canvas/refreshToken.ts index 72ebb4c148e4dd45d3e3d6e15191a758e9b7738e..1814488682f638f75f91e2b0a7c05742c07402a3 100644 --- a/Authentication/src/providers/Canvas/refreshToken.ts +++ b/Authentication/src/providers/Canvas/refreshToken.ts @@ -1,6 +1,7 @@ import { canvas, CLIENT_SECRET, CLIENT_ID } from './canvas'; import { IDatabaseEntry } from '../../lib/Database'; import { REDIRECT_URL } from '../../environment'; +import Resolvable, { IResolvable } from '../../lib/Resolvable'; export interface IResp { access_token: string; @@ -14,7 +15,21 @@ export interface IUser { name: string; } +const refreshing: Record<string, Array<IResolvable<IDatabaseEntry | null>>> = {}; export default async function refreshToken(refresh: string): Promise<IDatabaseEntry | null> { + const promise = Resolvable<IDatabaseEntry | null>(); + const firstRequest = !refreshing[refresh]; + + if (firstRequest) refreshing[refresh] = [promise]; + else refreshing[refresh].push(promise); + + if (firstRequest) actualRefreshToken(refresh); + return promise; +} + +async function actualRefreshToken(refresh: string) { + const respond = (v: IDatabaseEntry | null) => { for (const promise of refreshing[refresh]) promise.resolve(v); delete refreshing[refresh]; }; + const { data: resp, status } = await canvas.post<IResp>('/login/oauth2/token', { grant_type: 'refresh_token', client_id: CLIENT_ID, @@ -24,16 +39,16 @@ export default async function refreshToken(refresh: string): Promise<IDatabaseEn }, { validateStatus: () => true }); if (status !== 200) { console.info(`Refreshing token failed: [${status}] /login/oauth2/token - "${JSON.stringify(resp)}"`); - return null; + respond(null); } - return { + respond({ userName: resp.user.name, userId: resp.user.id, token: { access: resp.access_token, - expired: resp.expires_in + Date.now(), + expired: resp.expires_in * 1000 + Date.now(), refresh, }, - }; + }); } diff --git a/Authentication/src/router/self.ts b/Authentication/src/router/self.ts index edfd4790c6b17161fe9e77239daa07f0fcfdb147..72b32937f059538b568593e227a8aafdadd385f1 100644 --- a/Authentication/src/router/self.ts +++ b/Authentication/src/router/self.ts @@ -7,7 +7,7 @@ route.put('Create Self Session', '/self', async (ctx) => { const { ltiId } = ctx.request.body; ctx.assert(!!ltiId, 400, '[ltiId] Must be specified'); const session = new Session(ltiId); - ctx.assert(!!await session.getToken(true), 400, 'User\'s refresh token invalidated'); + ctx.assert(!!await session.getToken(), 400, 'User\'s refresh token invalidated'); ctx.body = session.id; }); diff --git a/Frontend/yarn.lock b/Frontend/yarn.lock index d2cac204cab3c81372d38a1a05f4f79119f600bd..b28e805d1c99e8f856c01e6083f5b480a1e54eb4 100644 --- a/Frontend/yarn.lock +++ b/Frontend/yarn.lock @@ -3895,7 +3895,7 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-eslint@10.0.3, babel-eslint@^10.0.3: +babel-eslint@10.0.3: version "10.0.3" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA== diff --git a/Makefile b/Makefile index bf1712277ad9e2826f8f07e78d1045fcf00e40f7..9ca94438435fcdb32a796c2b490dc435b4f497c0 100644 --- a/Makefile +++ b/Makefile @@ -14,10 +14,15 @@ start: stop: docker-compose down +update: install + install: - cd AquaSonde/; yarn --silent - cd Client/; yarn --silent - cd Database/; yarn --silent - cd Sponge/; yarn --silent - cd WaterLeveler/; yarn --silent + cd Authentication/; yarn --silent + cd Frontend/; sudo rm -rf node_modules/.cache/ + cd Frontend/; yarn --silent + cd Learning/; yarn --silent + cd Public/; pip install -r requirements.txt @echo "Finished installation" + + + diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity deleted file mode 100644 index 94105bd174d9b0fe8188179a9534271b7912a422..0000000000000000000000000000000000000000 --- a/node_modules/.yarn-integrity +++ /dev/null @@ -1,10 +0,0 @@ -{ - "systemParams": "linux-x64-79", - "modulesFolders": [], - "flags": [], - "linkedModules": [], - "topLevelPatterns": [], - "lockfileEntries": {}, - "files": [], - "artifacts": {} -} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000000000000000000000000000000000..fb57ccd13afbd082ad82051c2ffebef4840661ec --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + +