mirror of
https://github.com/zoriya/flood.git
synced 2026-05-29 18:04:10 +00:00
server: migrations: add migration for UserInDatabase2
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import {AccessLevel} from '../../../shared/schema/Auth';
|
||||
import Users from '../../models/Users';
|
||||
|
||||
import type {Credentials} from '../../../shared/schema/Auth';
|
||||
import type {RTorrentConnectionSettings} from '../../../shared/schema/ClientConnectionSettings';
|
||||
import type {UserInDatabase1} from './types/UserInDatabase1';
|
||||
|
||||
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 new Promise((resolve, _reject) => {
|
||||
Users.listUsers((users, err) => {
|
||||
if (users == null || err) {
|
||||
return;
|
||||
}
|
||||
|
||||
Promise.all(
|
||||
users.map((user) => {
|
||||
return new Promise((migratedResolve, _migratedReject) => {
|
||||
if (user.client != null) {
|
||||
// No need to migrate.
|
||||
migratedResolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const userV1 = (user as unknown) as UserInDatabase1;
|
||||
|
||||
let connectionSettings: RTorrentConnectionSettings | null = null;
|
||||
if (userV1.socketPath != null) {
|
||||
connectionSettings = {
|
||||
client: 'rTorrent',
|
||||
type: 'socket',
|
||||
version: 1,
|
||||
socket: userV1.socketPath,
|
||||
};
|
||||
} else if (userV1.host != null && userV1.port != null) {
|
||||
connectionSettings = {
|
||||
client: 'rTorrent',
|
||||
type: 'tcp',
|
||||
version: 1,
|
||||
host: userV1.host,
|
||||
port: userV1.port,
|
||||
};
|
||||
}
|
||||
|
||||
if (connectionSettings == null) {
|
||||
migrationError(new Error('Corrupted client connection settings.'));
|
||||
return;
|
||||
}
|
||||
|
||||
const userV2: Credentials = {
|
||||
username: userV1.username,
|
||||
password: userV1.password,
|
||||
client: connectionSettings,
|
||||
level: userV1.isAdmin ? AccessLevel.ADMINISTRATOR : AccessLevel.USER,
|
||||
};
|
||||
|
||||
Users.removeUser(userV1.username, (id, errRemoval) => {
|
||||
if (errRemoval) {
|
||||
migrationError(errRemoval);
|
||||
return;
|
||||
}
|
||||
|
||||
if (id == null) {
|
||||
migrationError(new Error('Wrong user ID'));
|
||||
return;
|
||||
}
|
||||
|
||||
Users.createUser(
|
||||
userV2,
|
||||
(_username, errCreation) => {
|
||||
if (errCreation) {
|
||||
migrationError(errCreation);
|
||||
}
|
||||
|
||||
migratedResolve();
|
||||
},
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
}),
|
||||
).then(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default migration;
|
||||
@@ -1,8 +1,6 @@
|
||||
const migrations = [
|
||||
() => {
|
||||
// do nothing. there is no migration at the moment.
|
||||
},
|
||||
];
|
||||
import UserInDatabase2 from './UserInDatabase2';
|
||||
|
||||
const migrations = [UserInDatabase2];
|
||||
|
||||
const migrate = () => Promise.all(migrations.map((migration) => migration()));
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Deprecated data structure. Not used outside of migration.
|
||||
export type UserInDatabase1 = {
|
||||
_id: string;
|
||||
username: string;
|
||||
password: string;
|
||||
host?: string | null;
|
||||
port?: number | null;
|
||||
socketPath?: string | null;
|
||||
isAdmin: boolean;
|
||||
};
|
||||
+5
-2
@@ -4,13 +4,16 @@ import chalk from 'chalk';
|
||||
|
||||
import enforcePrerequisites from './enforce-prerequisites';
|
||||
import migrateData from './migrations/run';
|
||||
import startWebServer from './web-server';
|
||||
|
||||
process.env.NODE_ENV = process.env.NODE_ENV !== 'development' ? 'production' : 'development';
|
||||
|
||||
enforcePrerequisites()
|
||||
.then(migrateData)
|
||||
.then(startWebServer)
|
||||
.then(() => {
|
||||
// We do this because we don't want the side effects of importing server functions before migration is completed.
|
||||
const startWebServer = require('./web-server').default; // eslint-disable-line global-require
|
||||
return startWebServer();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(chalk.red('Failed to start Flood:'));
|
||||
console.trace(error);
|
||||
|
||||
@@ -75,7 +75,8 @@ class Users {
|
||||
|
||||
createUser(
|
||||
credentials: Credentials,
|
||||
callback: (data: {username: Required<Credentials['username']>} | null, error?: Error) => void,
|
||||
callback: (user: UserInDatabase | null, error?: Error) => void,
|
||||
shouldHash = true,
|
||||
): void {
|
||||
if (this.db == null) {
|
||||
return callback(null, new Error('Users database is not ready.'));
|
||||
@@ -87,7 +88,7 @@ class Users {
|
||||
this.db.insert(
|
||||
{
|
||||
...credentials,
|
||||
password: hash.encoded,
|
||||
password: shouldHash ? hash.encoded : credentials.password,
|
||||
},
|
||||
(error, user) => {
|
||||
if (error) {
|
||||
@@ -98,8 +99,7 @@ class Users {
|
||||
return callback(null, error);
|
||||
}
|
||||
|
||||
services.bootstrapServicesForUser(user as UserInDatabase);
|
||||
return callback({username: credentials.username});
|
||||
return callback(user as UserInDatabase);
|
||||
},
|
||||
);
|
||||
})
|
||||
|
||||
@@ -92,11 +92,7 @@ router.post<unknown, unknown, AuthAuthenticationOptions>('/authenticate', (req,
|
||||
|
||||
const credentials = parsedResult.data;
|
||||
|
||||
Users.comparePassword(credentials, (isMatch, level, err) => {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
|
||||
Users.comparePassword(credentials, (isMatch, level, _err) => {
|
||||
if (isMatch === true && level != null) {
|
||||
sendAuthenticationResponse(res, {
|
||||
...credentials,
|
||||
@@ -164,14 +160,16 @@ router.post<unknown, unknown, AuthRegistrationOptions, {cookie: string}>('/regis
|
||||
const credentials = parsedResult.data;
|
||||
|
||||
// Attempt to save the user
|
||||
Users.createUser(credentials, (createUserResponse, createUserError) => {
|
||||
if (createUserError) {
|
||||
ajaxUtil.getResponseFn(res)(createUserResponse, createUserError);
|
||||
Users.createUser(credentials, (user, error) => {
|
||||
if (error || user == null) {
|
||||
ajaxUtil.getResponseFn(res)({username: credentials.username}, error);
|
||||
return;
|
||||
}
|
||||
|
||||
services.bootstrapServicesForUser(user);
|
||||
|
||||
if (req.query.cookie === 'false') {
|
||||
ajaxUtil.getResponseFn(res)(createUserResponse);
|
||||
ajaxUtil.getResponseFn(res)({username: user.username});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user