From 636c70ac9199cedbc75801f2270b7a96950423b9 Mon Sep 17 00:00:00 2001 From: Nils Streijffert Date: Thu, 11 Feb 2021 10:16:34 +0100 Subject: [PATCH] Use JS Date instead of Datetime --- .../src/identity/DatabaseKeyStore.test.ts | 3 ++- .../src/identity/DatabaseKeyStore.ts | 16 +++++++++++++--- .../auth-backend/src/identity/MemoryKeyStore.ts | 4 ++-- .../auth-backend/src/identity/TokenFactory.ts | 10 +++++----- plugins/auth-backend/src/identity/types.ts | 3 +-- 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts b/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts index ec886856fe..3c61e20c1c 100644 --- a/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts +++ b/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts @@ -16,6 +16,7 @@ import Knex from 'knex'; import { DatabaseKeyStore } from './DatabaseKeyStore'; +import { DateTime } from 'luxon' function createDB() { const knex = Knex({ @@ -51,7 +52,7 @@ describe('DatabaseKeyStore', () => { const { items } = await store.listKeys(); expect(items).toEqual([{ createdAt: expect.anything(), key }]); expect( - Math.abs(items[0].createdAt.diffNow('seconds').seconds), + Math.abs(DateTime.fromJSDate(items[0].createdAt).diffNow('seconds').seconds), ).toBeLessThan(10); }); diff --git a/plugins/auth-backend/src/identity/DatabaseKeyStore.ts b/plugins/auth-backend/src/identity/DatabaseKeyStore.ts index 6aad9af30f..6ffb840e6d 100644 --- a/plugins/auth-backend/src/identity/DatabaseKeyStore.ts +++ b/plugins/auth-backend/src/identity/DatabaseKeyStore.ts @@ -66,9 +66,7 @@ export class DatabaseKeyStore implements KeyStore { return { items: rows.map(row => ({ key: JSON.parse(row.key), - createdAt: DateTime.fromSQL((row.created_at as unknown) as string, { - zone: 'UTC', - }), + createdAt: parseDate(row.created_at), })), }; } @@ -77,3 +75,15 @@ export class DatabaseKeyStore implements KeyStore { await this.database(TABLE).delete().whereIn('kid', kids); } } + +const parseDate = (date: string | Date) => { + const parsedDate = typeof date === 'string' ? DateTime.fromSQL(date, {locale: 'UTC'}) : DateTime.fromJSDate(date) + + if (!parsedDate.isValid) { + throw new Error( + `Failed to parse date, reason: ${parsedDate.invalidReason}, explanation: ${parsedDate.invalidExplanation}`, + ); + } + + return parsedDate.toJSDate() +} \ No newline at end of file diff --git a/plugins/auth-backend/src/identity/MemoryKeyStore.ts b/plugins/auth-backend/src/identity/MemoryKeyStore.ts index ecb31d9998..efb81cd264 100644 --- a/plugins/auth-backend/src/identity/MemoryKeyStore.ts +++ b/plugins/auth-backend/src/identity/MemoryKeyStore.ts @@ -20,12 +20,12 @@ import { DateTime } from 'luxon'; export class MemoryKeyStore implements KeyStore { private readonly keys = new Map< string, - { createdAt: DateTime; key: string } + { createdAt: Date; key: string } >(); async addKey(key: AnyJWK): Promise { this.keys.set(key.kid, { - createdAt: DateTime.utc(), + createdAt: DateTime.utc().toJSDate(), key: JSON.stringify(key), }); } diff --git a/plugins/auth-backend/src/identity/TokenFactory.ts b/plugins/auth-backend/src/identity/TokenFactory.ts index 99ea26a7fb..4169484191 100644 --- a/plugins/auth-backend/src/identity/TokenFactory.ts +++ b/plugins/auth-backend/src/identity/TokenFactory.ts @@ -52,7 +52,7 @@ export class TokenFactory implements TokenIssuer { private readonly keyStore: KeyStore; private readonly keyDurationSeconds: number; - private keyExpiry?: DateTime; + private keyExpiry?: Date; private privateKeyPromise?: Promise; constructor(options: Options) { @@ -90,7 +90,7 @@ export class TokenFactory implements TokenIssuer { for (const key of keys) { // Allow for a grace period of another full key duration before we remove the keys from the database - const expireAt = key.createdAt.plus({ + const expireAt = DateTime.fromJSDate(key.createdAt).plus({ seconds: 3 * this.keyDurationSeconds, }); if (expireAt < DateTime.local()) { @@ -119,16 +119,16 @@ export class TokenFactory implements TokenIssuer { private async getKey(): Promise { // Make sure that we only generate one key at a time if (this.privateKeyPromise) { - if (this.keyExpiry && this.keyExpiry > DateTime.local()) { + if (this.keyExpiry && DateTime.fromJSDate(this.keyExpiry) > DateTime.local()) { return this.privateKeyPromise; } this.logger.info(`Signing key has expired, generating new key`); delete this.privateKeyPromise; } - this.keyExpiry = DateTime.local().plus({ + this.keyExpiry = DateTime.utc().plus({ seconds: this.keyDurationSeconds, - }); + }).toJSDate(); const promise = (async () => { // This generates a new signing key to be used to sign tokens until the next key rotation const key = await JWK.generate('EC', 'P-256', { diff --git a/plugins/auth-backend/src/identity/types.ts b/plugins/auth-backend/src/identity/types.ts index 4e3eeb872e..6e984d41cc 100644 --- a/plugins/auth-backend/src/identity/types.ts +++ b/plugins/auth-backend/src/identity/types.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { DateTime } from 'luxon'; /** Represents any form of serializable JWK */ export interface AnyJWK extends Record { @@ -53,7 +52,7 @@ export type TokenIssuer = { */ export type StoredKey = { key: AnyJWK; - createdAt: DateTime; + createdAt: Date; }; /**