From f5bb221ecdcaa40948df6a12ce94c793b5d099ac Mon Sep 17 00:00:00 2001 From: Haidang666 Date: Sun, 27 Jun 2021 11:45:42 +0700 Subject: [PATCH 1/3] Add log when update username --- databases/_upgrade_private_2.sql | 13 ++++++++ src/routes/setUsername.ts | 17 ++++++++-- test/cases/setUsername.ts | 57 +++++++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 databases/_upgrade_private_2.sql diff --git a/databases/_upgrade_private_2.sql b/databases/_upgrade_private_2.sql new file mode 100644 index 0000000..1a70e67 --- /dev/null +++ b/databases/_upgrade_private_2.sql @@ -0,0 +1,13 @@ +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS "userNameLogs" ( + "userID" TEXT NOT NULL, + "newUserName" TEXT NOT NULL, + "oldUserName" TEXT NOT NULL, + "updatedByAdmin" BOOLEAN NOT NULL, + "updatedAt" INTEGER NOT NULL +); + +UPDATE "config" SET value = 2 WHERE key = 'version'; + +COMMIT; \ No newline at end of file diff --git a/src/routes/setUsername.ts b/src/routes/setUsername.ts index fdd99dc..2a0e75b 100644 --- a/src/routes/setUsername.ts +++ b/src/routes/setUsername.ts @@ -1,9 +1,16 @@ import {config} from '../config'; import {Logger} from '../utils/logger'; -import {db} from '../databases/databases'; +import {db, privateDB} from '../databases/databases'; import {getHash} from '../utils/getHash'; import {Request, Response} from 'express'; +async function logUserNameChange(userID: string, newUserName: string, oldUserName: string, updatedByAdmin: boolean): Promise { + return privateDB.prepare('run', + `INSERT INTO "userNameLogs"("userID", "newUserName", "oldUserName", "updatedByAdmin", "updatedAt") VALUES(?, ?, ?, ?, ?)`, + [userID, newUserName, oldUserName, + updatedByAdmin, new Date().getTime()] + ); +} + export async function setUsername(req: Request, res: Response) { let userID = req.query.userID as string; let userName = req.query.username as string; @@ -55,16 +62,20 @@ export async function setUsername(req: Request, res: Response) { try { //check if username is already set - let row = await db.prepare('get', `SELECT count(*) as count FROM "userNames" WHERE "userID" = ?`, [userID]); + let row = await db.prepare('get', `SELECT userName FROM "userNames" WHERE "userID" = ? LIMIT 1`, [userID]); + let oldUserName = ''; - if (row.count > 0) { + if (row.userName && row.userName.length !== 0) { //already exists, update this row + oldUserName = row.userName; await db.prepare('run', `UPDATE "userNames" SET "userName" = ? WHERE "userID" = ?`, [userName, userID]); } else { //add to the db await db.prepare('run', `INSERT INTO "userNames"("userID", "userName") VALUES(?, ?)`, [userID, userName]); } + await logUserNameChange(userID, userName, oldUserName, adminUserIDInput !== undefined); + res.sendStatus(200); } catch (err) { Logger.error(err); diff --git a/test/cases/setUsername.ts b/test/cases/setUsername.ts index ae3a8f5..d82c121 100644 --- a/test/cases/setUsername.ts +++ b/test/cases/setUsername.ts @@ -1,6 +1,6 @@ import fetch from 'node-fetch'; import { Done, getbaseURL } from '../utils'; -import { db } from '../../src/databases/databases'; +import { db, privateDB } from '../../src/databases/databases'; import { getHash } from '../../src/utils/getHash'; const adminPrivateUserID = 'testUserId'; @@ -21,6 +21,7 @@ const username07 = 'Username 07'; async function addUsername(userID: string, userName: string, locked = 0) { await db.prepare('run', 'INSERT INTO "userNames" ("userID", "userName", "locked") VALUES(?, ?, ?)', [userID, userName, locked]); + await addLogUserNameChange(userID, userName); } async function getUsername(userID: string) { @@ -31,6 +32,40 @@ async function getUsername(userID: string) { return row.userName; } +async function addLogUserNameChange(userID: string, newUserName: string, oldUserName: string = '') { + privateDB.prepare('run', + `INSERT INTO "userNameLogs"("userID", "newUserName", "oldUserName", "updatedAt", "updatedByAdmin") VALUES(?, ?, ?, ?, ?)`, + [getHash(userID), newUserName, oldUserName, new Date().getTime(), + true] + ); +} + +async function getLastLogUserNameChange(userID: string) { + return privateDB.prepare('get', `SELECT * FROM "userNameLogs" WHERE "userID" = ? ORDER BY "updatedAt" DESC LIMIT 1`, [getHash(userID)]); +} + +function wellFormatUserName(userName: string) { + return userName.replace(/[\u0000-\u001F\u007F-\u009F]/g, ''); +} + +async function testUserNameChangelog(userID: string, newUserName: string, oldUserName: string, byAdmin: boolean, done: Done) { + + const log = await getLastLogUserNameChange(userID); + + if (newUserName !== log.newUserName) { + return done(`UserID '${userID}' incorrect log on newUserName: ${newUserName} !== ${log.newUserName}`); + } + + if (oldUserName !== log.oldUserName) { + return done(`UserID '${userID}' incorrect log on oldUserName: ${oldUserName} !== ${log.oldUserName}`); + } + + if (+byAdmin !== log.updatedByAdmin) { + return done(`UserID '${userID}' incorrect log on updatedByAdmin: ${byAdmin} !== ${log.updatedByAdmin}`); + } + + return done(); +} + describe('setUsername', () => { before(async () => { await addUsername(getHash(user01PrivateUserID), username01, 0); @@ -46,9 +81,11 @@ describe('setUsername', () => { fetch(`${getbaseURL()}/api/setUsername?userID=${user01PrivateUserID}&username=Changed%20Username`, { method: 'POST', }) - .then(res => { + .then(async res => { if (res.status !== 200) done(`Status code was ${res.status}`); - else done(); // pass + else { + testUserNameChangelog(user01PrivateUserID, decodeURIComponent('Changed%20Username'), username01, false, done); + } }) .catch(err => done(`couldn't call endpoint`)); }); @@ -113,7 +150,9 @@ describe('setUsername', () => { .then(async res => { const username = await getUsername(getHash(user03PrivateUserID)); if (username !== newUsername) done(`Username did not change`); - else done(); + else { + testUserNameChangelog(user03PrivateUserID, newUsername, username03, false, done); + } }) .catch(err => done(`couldn't call endpoint`)); }); @@ -139,7 +178,7 @@ describe('setUsername', () => { .then(async res => { const username = await getUsername(getHash(user05PrivateUserID)); if (username === newUsername) done(`Username contains unicode control characters`); - else done(); + else testUserNameChangelog(user05PrivateUserID, wellFormatUserName(newUsername), username05, false, done); }) .catch(err => done(`couldn't call endpoint`)); }); @@ -164,7 +203,7 @@ describe('setUsername', () => { .then(async res => { const username = await getUsername(getHash(user06PrivateUserID)); if (username !== newUsername) done(`Failed to change username from '${username06}' to '${newUsername}'`); - else done(); + else testUserNameChangelog(user06PrivateUserID, newUsername, username06, true, done); }) .catch(err => done(`couldn't call endpoint`)); }); @@ -175,9 +214,9 @@ describe('setUsername', () => { method: 'POST', }) .then(async res => { - const username = await getUsername(getHash(user06PrivateUserID)); - if (username !== newUsername) done(`Failed to change username from '${username06}' to '${newUsername}'`); - else done(); + const username = await getUsername(getHash(user07PrivateUserID)); + if (username !== newUsername) done(`Failed to change username from '${username07}' to '${newUsername}'`); + else testUserNameChangelog(user07PrivateUserID, newUsername, username07, true, done); }) .catch(err => done(`couldn't call endpoint`)); }); From f3542b74029631f45a9737e816a8b7f3b7bc3d87 Mon Sep 17 00:00:00 2001 From: Haidang666 Date: Sun, 27 Jun 2021 11:51:04 +0700 Subject: [PATCH 2/3] Fix column name for postgre --- src/routes/setUsername.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/setUsername.ts b/src/routes/setUsername.ts index 2a0e75b..dbcdd91 100644 --- a/src/routes/setUsername.ts +++ b/src/routes/setUsername.ts @@ -62,7 +62,7 @@ export async function setUsername(req: Request, res: Response) { try { //check if username is already set - let row = await db.prepare('get', `SELECT userName FROM "userNames" WHERE "userID" = ? LIMIT 1`, [userID]); + let row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ? LIMIT 1`, [userID]); let oldUserName = ''; if (row.userName && row.userName.length !== 0) { From 41ba37c04eb46885ee8b8bdf26af9b78e24b3103 Mon Sep 17 00:00:00 2001 From: Haidang666 Date: Sun, 27 Jun 2021 11:57:39 +0700 Subject: [PATCH 3/3] Fix boolean comparison, Add log table to schema visual --- DatabaseSchema.md | 11 +++++++++++ test/cases/setUsername.ts | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/DatabaseSchema.md b/DatabaseSchema.md index 32fdc6e..16aa6f8 100644 --- a/DatabaseSchema.md +++ b/DatabaseSchema.md @@ -3,6 +3,7 @@ [vipUsers](###vipUsers) [sponsorTimes](###sponsorTimes) [userNames](###userNames) +[userNameLogs](###userNameLogs) [categoryVotes](###categoryVotes) [lockCategories](###lockCategories) [warnings](###warnings) @@ -61,6 +62,16 @@ | -- | :--: | | userNames_userID | userID | +### userNameLogs + +| Name | Type | | +| -- | :--: | -- | +| userID | TEXT | not null | +| newUserName | TEXT | not null | +| oldUserName | TEXT | not null | +| updatedByAdmin | BOOLEAN | not null | +| updatedAt | INTEGER | not null | + ### categoryVotes | Name | Type | | diff --git a/test/cases/setUsername.ts b/test/cases/setUsername.ts index d82c121..286cee8 100644 --- a/test/cases/setUsername.ts +++ b/test/cases/setUsername.ts @@ -59,7 +59,7 @@ async function testUserNameChangelog(userID: string, newUserName: string, oldUse return done(`UserID '${userID}' incorrect log on oldUserName: ${oldUserName} !== ${log.oldUserName}`); } - if (+byAdmin !== log.updatedByAdmin) { + if (byAdmin !== Boolean(log.updatedByAdmin)) { return done(`UserID '${userID}' incorrect log on updatedByAdmin: ${byAdmin} !== ${log.updatedByAdmin}`); }