mirror of
https://github.com/fosrl/pangolin.git
synced 2025-07-01 01:24:51 +02:00
add set server admin password to cli
This commit is contained in:
parent
ddd292422b
commit
fc19d0ba8b
9 changed files with 172 additions and 5 deletions
141
cli/commands/setAdminCredentials.ts
Normal file
141
cli/commands/setAdminCredentials.ts
Normal file
|
@ -0,0 +1,141 @@
|
|||
import { CommandModule } from "yargs";
|
||||
import { hashPassword, verifyPassword } from "@server/auth/password";
|
||||
import { db, resourceSessions, sessions } from "@server/db";
|
||||
import { users } from "@server/db";
|
||||
import { eq, inArray } from "drizzle-orm";
|
||||
import moment from "moment";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { passwordSchema } from "@server/auth/passwordSchema";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
import { generateRandomString, RandomReader } from "@oslojs/crypto/random";
|
||||
|
||||
type SetAdminCredentialsArgs = {
|
||||
email: string;
|
||||
password: string;
|
||||
};
|
||||
|
||||
export const setAdminCredentials: CommandModule<{}, SetAdminCredentialsArgs> = {
|
||||
command: "set-admin-credentials",
|
||||
describe: "Set the server admin credentials",
|
||||
builder: (yargs) => {
|
||||
return yargs
|
||||
.option("email", {
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
describe: "Admin email address"
|
||||
})
|
||||
.option("password", {
|
||||
type: "string",
|
||||
demandOption: true,
|
||||
describe: "Admin password"
|
||||
});
|
||||
},
|
||||
handler: async (argv: { email: string; password: string }) => {
|
||||
try {
|
||||
const { email, password } = argv;
|
||||
|
||||
const parsed = passwordSchema.safeParse(password);
|
||||
|
||||
if (!parsed.success) {
|
||||
throw Error(
|
||||
`Invalid server admin password: ${fromError(parsed.error).toString()}`
|
||||
);
|
||||
}
|
||||
|
||||
const passwordHash = await hashPassword(password);
|
||||
|
||||
await db.transaction(async (trx) => {
|
||||
try {
|
||||
const [existing] = await trx
|
||||
.select()
|
||||
.from(users)
|
||||
.where(eq(users.serverAdmin, true));
|
||||
|
||||
if (existing) {
|
||||
const passwordChanged = !(await verifyPassword(
|
||||
password,
|
||||
existing.passwordHash!
|
||||
));
|
||||
|
||||
if (passwordChanged) {
|
||||
await trx
|
||||
.update(users)
|
||||
.set({ passwordHash })
|
||||
.where(eq(users.userId, existing.userId));
|
||||
|
||||
await invalidateAllSessions(existing.userId);
|
||||
console.log("Server admin password updated");
|
||||
}
|
||||
|
||||
if (existing.email !== email) {
|
||||
await trx
|
||||
.update(users)
|
||||
.set({ email, username: email })
|
||||
.where(eq(users.userId, existing.userId));
|
||||
|
||||
console.log("Server admin email updated");
|
||||
}
|
||||
} else {
|
||||
const userId = generateId(15);
|
||||
|
||||
await trx.update(users).set({ serverAdmin: false });
|
||||
|
||||
await db.insert(users).values({
|
||||
userId: userId,
|
||||
email: email,
|
||||
type: UserType.Internal,
|
||||
username: email,
|
||||
passwordHash,
|
||||
dateCreated: moment().toISOString(),
|
||||
serverAdmin: true,
|
||||
emailVerified: true
|
||||
});
|
||||
|
||||
console.log("Server admin created");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to set admin credentials", e);
|
||||
trx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Admin credentials updated successfully");
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export async function invalidateAllSessions(userId: string): Promise<void> {
|
||||
try {
|
||||
await db.transaction(async (trx) => {
|
||||
const userSessions = await trx
|
||||
.select()
|
||||
.from(sessions)
|
||||
.where(eq(sessions.userId, userId));
|
||||
await trx.delete(resourceSessions).where(
|
||||
inArray(
|
||||
resourceSessions.userSessionId,
|
||||
userSessions.map((s) => s.sessionId)
|
||||
)
|
||||
);
|
||||
await trx.delete(sessions).where(eq(sessions.userId, userId));
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Failed to all invalidate user sessions", e);
|
||||
}
|
||||
}
|
||||
|
||||
const random: RandomReader = {
|
||||
read(bytes: Uint8Array): void {
|
||||
crypto.getRandomValues(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
export function generateId(length: number): string {
|
||||
const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
return generateRandomString(random, alphabet, length);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue