server: invalidate previous tokens when user changed

This commit is contained in:
Jesse Chan
2021-01-26 08:57:38 +08:00
parent 53c0b3f863
commit 402a5b8a69
5 changed files with 43 additions and 6 deletions
+28
View File
@@ -0,0 +1,28 @@
import Users from '../../models/Users';
const migrationError = (err?: Error) => {
if (err) {
console.error(err);
}
console.error('Migration failed. You need to reset the databases manually.');
process.exit();
};
const migration = () => {
return Users.listUsers().then((users) => {
return Promise.all(
users.map(async (user) => {
if (user.timestamp != null) {
// No need to migrate.
return;
}
await Users.updateUser(user.username, {});
}),
).catch((err) => {
migrationError(err);
});
});
};
export default migration;
+2 -1
View File
@@ -1,6 +1,7 @@
import UserInDatabase2 from './UserInDatabase2';
import UserInDatabase3 from './UserInDatabase3';
const migrations = [UserInDatabase2];
const migrations = [UserInDatabase2, UserInDatabase3];
const migrate = () => Promise.all(migrations.map((migration) => migration()));
+5 -1
View File
@@ -26,7 +26,11 @@ export default (passport: PassportStatic) => {
Users.lookupUser(parsedResult.data.username).then(
(user) => {
callback(null, user);
if (user?.timestamp <= parsedResult.data.iat + 10) {
callback(null, user);
} else {
callback(new Error(), false);
}
},
(err) => {
callback(err, false);
+7 -3
View File
@@ -37,6 +37,7 @@ class Users {
private configUser: UserInDatabase = {
_id: '_config',
timestamp: 0,
username: '_config',
password: '',
client: config.configUser as ClientConnectionSettings,
@@ -105,6 +106,7 @@ class Users {
.insert({
...credentials,
password: hashed,
timestamp: Math.ceil(Date.now() / 1000),
})
.catch((err) => {
if (err.message.includes('violates the unique constraint')) {
@@ -139,12 +141,14 @@ class Users {
* @return {Promise<string>} - Returns new username of updated user or rejects with error.
*/
async updateUser(username: string, userRecordPatch: Partial<Credentials>): Promise<string> {
const patch = userRecordPatch;
const patch: Omit<Partial<UserInDatabase>, '_id'> = userRecordPatch;
if (patch.password != null) {
patch.password = await hashPassword(patch.password);
}
patch.timestamp = Math.ceil(Date.now() / 1000);
return this.db.update({username}, {$set: patch}, {}).then((numUsersUpdated) => {
if (numUsersUpdated === 0) {
throw new Error();
@@ -165,7 +169,7 @@ class Users {
return this.getConfigUser();
}
return this.db.findOne<Credentials>({username});
return this.db.findOne<UserInDatabase>({username});
}
/**
@@ -178,7 +182,7 @@ class Users {
return [this.getConfigUser()];
}
return this.db.find<Credentials>({});
return this.db.find<UserInDatabase>({});
}
/**
+1 -1
View File
@@ -17,7 +17,7 @@ export const credentialsSchema = object({
export type Credentials = zodInfer<typeof credentialsSchema>;
export type UserInDatabase = Required<Credentials> & {_id: string};
export type UserInDatabase = Required<Credentials> & {_id: string; timestamp: number};
export const authTokenSchema = object({
username: string(),