From 73cb644efb431e567b06f0b3b97b689f4b183e21 Mon Sep 17 00:00:00 2001 From: James Gregory Date: Fri, 30 Jul 2021 08:17:53 +1000 Subject: [PATCH] fix: regression for usernames with full stops in The change introduced in ece63ba to separate Username and Sub meant that usernames with full stops in stopped working with StormDB, as it interpreted the full stop as a path separator. This updates our use of StormDB so it doesn't parse the keys for separators. Fixes #35 --- integration-tests/dataStore.test.ts | 16 +- integration-tests/userPoolClient.test.ts | 242 ++++++++++++----------- src/services/dataStore.ts | 5 +- 3 files changed, 141 insertions(+), 122 deletions(-) diff --git a/integration-tests/dataStore.test.ts b/integration-tests/dataStore.test.ts index 92e2734d..d1545e6e 100644 --- a/integration-tests/dataStore.test.ts +++ b/integration-tests/dataStore.test.ts @@ -56,10 +56,10 @@ describe("Data Store", () => { }); }); - it("saves a nested value", async () => { + it("saves a nested value using array syntax", async () => { const dataStore = await createDataStore("example", {}, path); - await dataStore.set("key.a.b", 1); + await dataStore.set(["key", "a", "b"], 1); const file = JSON.parse(await readFile(path + "/example.json", "utf-8")); @@ -72,6 +72,18 @@ describe("Data Store", () => { }); }); + it("saves a key with dots in as a single key-value pair", async () => { + const dataStore = await createDataStore("example", {}, path); + + await dataStore.set("key.a.b", 1); + + const file = JSON.parse(await readFile(path + "/example.json", "utf-8")); + + expect(file).toEqual({ + "key.a.b": 1, + }); + }); + it("replaces a value", async () => { const dataStore = await createDataStore("example", {}, path); diff --git a/integration-tests/userPoolClient.test.ts b/integration-tests/userPoolClient.test.ts index e8e6ae13..5f66bdc7 100644 --- a/integration-tests/userPoolClient.test.ts +++ b/integration-tests/userPoolClient.test.ts @@ -13,6 +13,8 @@ const mkdtemp = promisify(fs.mkdtemp); const readFile = promisify(fs.readFile); const rmdir = promisify(fs.rmdir); +const validUsernameExamples = ["ExampleUsername", "example.username"]; + describe("User Pool Client", () => { let path: string; let tmpCreateDataStore: CreateDataStore; @@ -45,149 +47,153 @@ describe("User Pool Client", () => { }); describe("saveUser", () => { - it("saves the user", async () => { - const now = new Date().getTime(); - const userPool = await cognitoClient.getUserPool("local"); + describe.each(validUsernameExamples)("with username %s", (username) => { + it("saves the user", async () => { + const now = new Date().getTime(); + const userPool = await cognitoClient.getUserPool("local"); - await userPool.saveUser({ - Username: "1", - Password: "hunter3", - UserStatus: "UNCONFIRMED", - Attributes: [ - { Name: "sub", Value: "uuid-1234" }, - { Name: "email", Value: "example@example.com" }, - ], - UserLastModifiedDate: now, - UserCreateDate: now, - Enabled: true, - }); + await userPool.saveUser({ + Username: username, + Password: "hunter3", + UserStatus: "UNCONFIRMED", + Attributes: [ + { Name: "sub", Value: "uuid-1234" }, + { Name: "email", Value: "example@example.com" }, + ], + UserLastModifiedDate: now, + UserCreateDate: now, + Enabled: true, + }); - const file = JSON.parse(await readFile(path + "/local.json", "utf-8")); + const file = JSON.parse(await readFile(path + "/local.json", "utf-8")); - expect(file).toEqual({ - Options: { Id: "local", UsernameAttributes: [] }, - Users: { - "1": { - Username: "1", - Password: "hunter3", - UserStatus: "UNCONFIRMED", - Attributes: [ - { Name: "sub", Value: "uuid-1234" }, - { Name: "email", Value: "example@example.com" }, - ], - UserLastModifiedDate: now, - UserCreateDate: now, - Enabled: true, + expect(file).toEqual({ + Options: { Id: "local", UsernameAttributes: [] }, + Users: { + [username]: { + Username: username, + Password: "hunter3", + UserStatus: "UNCONFIRMED", + Attributes: [ + { Name: "sub", Value: "uuid-1234" }, + { Name: "email", Value: "example@example.com" }, + ], + UserLastModifiedDate: now, + UserCreateDate: now, + Enabled: true, + }, }, - }, + }); }); - }); - it("updates a user", async () => { - const now = new Date().getTime(); - const userPool = await cognitoClient.getUserPool("local"); + it("updates a user", async () => { + const now = new Date().getTime(); + const userPool = await cognitoClient.getUserPool("local"); - await userPool.saveUser({ - Username: "1", - Password: "hunter3", - UserStatus: "UNCONFIRMED", - ConfirmationCode: "1234", - Attributes: [ - { Name: "sub", Value: "uuid-1234" }, - { Name: "email", Value: "example@example.com" }, - ], - UserLastModifiedDate: now, - UserCreateDate: now, - Enabled: true, - }); + await userPool.saveUser({ + Username: username, + Password: "hunter3", + UserStatus: "UNCONFIRMED", + ConfirmationCode: "1234", + Attributes: [ + { Name: "sub", Value: "uuid-1234" }, + { Name: "email", Value: "example@example.com" }, + ], + UserLastModifiedDate: now, + UserCreateDate: now, + Enabled: true, + }); - let file = JSON.parse(await readFile(path + "/local.json", "utf-8")); + let file = JSON.parse(await readFile(path + "/local.json", "utf-8")); - expect(file).toEqual({ - Options: { Id: "local", UsernameAttributes: [] }, - Users: { - "1": { - Username: "1", - Password: "hunter3", - UserStatus: "UNCONFIRMED", - ConfirmationCode: "1234", - Attributes: [ - { Name: "sub", Value: "uuid-1234" }, - { Name: "email", Value: "example@example.com" }, - ], - UserLastModifiedDate: now, - UserCreateDate: now, - Enabled: true, + expect(file).toEqual({ + Options: { Id: "local", UsernameAttributes: [] }, + Users: { + [username]: { + Username: username, + Password: "hunter3", + UserStatus: "UNCONFIRMED", + ConfirmationCode: "1234", + Attributes: [ + { Name: "sub", Value: "uuid-1234" }, + { Name: "email", Value: "example@example.com" }, + ], + UserLastModifiedDate: now, + UserCreateDate: now, + Enabled: true, + }, }, - }, - }); + }); - await userPool.saveUser({ - Username: "1", - Password: "hunter3", - UserStatus: "CONFIRMED", - Attributes: [ - { Name: "sub", Value: "uuid-1234" }, - { Name: "email", Value: "example@example.com" }, - ], - UserLastModifiedDate: now, - UserCreateDate: now, - Enabled: true, - }); + await userPool.saveUser({ + Username: username, + Password: "hunter3", + UserStatus: "CONFIRMED", + Attributes: [ + { Name: "sub", Value: "uuid-1234" }, + { Name: "email", Value: "example@example.com" }, + ], + UserLastModifiedDate: now, + UserCreateDate: now, + Enabled: true, + }); - file = JSON.parse(await readFile(path + "/local.json", "utf-8")); + file = JSON.parse(await readFile(path + "/local.json", "utf-8")); - expect(file).toEqual({ - Options: { Id: "local", UsernameAttributes: [] }, - Users: { - "1": { - Username: "1", - Password: "hunter3", - UserStatus: "CONFIRMED", - Attributes: [ - { Name: "sub", Value: "uuid-1234" }, - { Name: "email", Value: "example@example.com" }, - ], - UserLastModifiedDate: now, - UserCreateDate: now, - Enabled: true, + expect(file).toEqual({ + Options: { Id: "local", UsernameAttributes: [] }, + Users: { + [username]: { + Username: username, + Password: "hunter3", + UserStatus: "CONFIRMED", + Attributes: [ + { Name: "sub", Value: "uuid-1234" }, + { Name: "email", Value: "example@example.com" }, + ], + UserLastModifiedDate: now, + UserCreateDate: now, + Enabled: true, + }, }, - }, + }); }); }); }); describe("getUserByUsername", () => { - let userPool: UserPoolClient; - beforeAll(async () => { - userPool = await cognitoClient.getUserPool("local"); + describe.each(validUsernameExamples)("with username %s", (username) => { + let userPool: UserPoolClient; + beforeAll(async () => { + userPool = await cognitoClient.getUserPool("local"); - await userPool.saveUser({ - Username: "1", - Password: "hunter2", - UserStatus: "UNCONFIRMED", - Attributes: [ - { Name: "sub", Value: "uuid-1234" }, - { Name: "email", Value: "example@example.com" }, - { Name: "phone_number", Value: "0411000111" }, - ], - UserCreateDate: new Date().getTime(), - UserLastModifiedDate: new Date().getTime(), - Enabled: true, + await userPool.saveUser({ + Username: username, + Password: "hunter2", + UserStatus: "UNCONFIRMED", + Attributes: [ + { Name: "sub", Value: "uuid-1234" }, + { Name: "email", Value: "example@example.com" }, + { Name: "phone_number", Value: "0411000111" }, + ], + UserCreateDate: new Date().getTime(), + UserLastModifiedDate: new Date().getTime(), + Enabled: true, + }); }); - }); - it("returns null if user doesn't exist", async () => { - const user = await userPool.getUserByUsername("invalid"); + it("returns null if user doesn't exist", async () => { + const user = await userPool.getUserByUsername("invalid"); - expect(user).toBeNull(); - }); + expect(user).toBeNull(); + }); - it("returns existing user by their sub attribute", async () => { - const user = await userPool.getUserByUsername("1"); + it("returns existing user by their username", async () => { + const user = await userPool.getUserByUsername(username); - expect(user).not.toBeNull(); - expect(user?.Username).toEqual("1"); + expect(user).not.toBeNull(); + expect(user?.Username).toEqual(username); + }); }); }); diff --git a/src/services/dataStore.ts b/src/services/dataStore.ts index 5bf37207..88056d79 100644 --- a/src/services/dataStore.ts +++ b/src/services/dataStore.ts @@ -39,7 +39,7 @@ export const createDataStore: CreateDataStore = async ( async get(key: string | string[], defaultValue?: unknown) { return ( (await (key instanceof Array ? key : [key]) - .reduce((acc, k) => acc.get(k), db) + .reduce((acc, k) => acc.get([k]), db) .value()) ?? defaultValue ?? null @@ -47,7 +47,8 @@ export const createDataStore: CreateDataStore = async ( }, async set(key, value) { - await db.set(key instanceof Array ? key.join(".") : key, value).save(); + db.setValue(value, key instanceof Array ? key : [key]); + await db.save(); }, }; };