This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { pathToFileURL } from 'node:url'
|
||||
|
||||
import {
|
||||
issueOperatorPasswordResetToken,
|
||||
TokenDigester,
|
||||
type IssueOperatorPasswordResetRequest,
|
||||
type IssuedPasswordReset,
|
||||
} from '@devrunbook/application'
|
||||
import { closeDatabase, DrizzlePasswordResetStore } from '@devrunbook/db'
|
||||
|
||||
type IssueReset = (
|
||||
request: IssueOperatorPasswordResetRequest,
|
||||
) => Promise<IssuedPasswordReset>
|
||||
|
||||
export async function runOperatorPasswordReset(
|
||||
arguments_: readonly string[],
|
||||
environment: Record<string, string | undefined>,
|
||||
writeOutput: (value: string) => void,
|
||||
issueReset?: IssueReset,
|
||||
): Promise<void> {
|
||||
if (arguments_.length !== 1 || !arguments_[0]) {
|
||||
throw new Error(
|
||||
'Usage: pnpm --filter @devrunbook/worker operator:password-reset -- <user-email>',
|
||||
)
|
||||
}
|
||||
const sessionSecret = environment.SESSION_SECRET
|
||||
const publicBaseUrl = environment.PUBLIC_BASE_URL
|
||||
if (!sessionSecret || sessionSecret.length < 32) {
|
||||
throw new Error('SESSION_SECRET must contain at least 32 characters')
|
||||
}
|
||||
if (!publicBaseUrl) throw new Error('PUBLIC_BASE_URL is required')
|
||||
|
||||
const issue =
|
||||
issueReset ??
|
||||
((request) =>
|
||||
issueOperatorPasswordResetToken(
|
||||
{
|
||||
store: new DrizzlePasswordResetStore(),
|
||||
digester: new TokenDigester(Buffer.from(sessionSecret, 'utf8')),
|
||||
},
|
||||
request,
|
||||
))
|
||||
const result = await issue({
|
||||
email: arguments_[0],
|
||||
publicBaseUrl,
|
||||
})
|
||||
|
||||
// Successful stdout is deliberately one line containing only the reset URL.
|
||||
writeOutput(result.resetUrl)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await runOperatorPasswordReset(
|
||||
process.argv.slice(2),
|
||||
process.env,
|
||||
(value) => console.log(value),
|
||||
)
|
||||
} catch (error) {
|
||||
const message =
|
||||
error instanceof Error ? error.message : 'Password reset failed'
|
||||
console.error(message)
|
||||
process.exitCode = 1
|
||||
} finally {
|
||||
await closeDatabase()
|
||||
}
|
||||
}
|
||||
|
||||
const entryPoint = process.argv[1]
|
||||
if (entryPoint && import.meta.url === pathToFileURL(entryPoint).href) {
|
||||
await main()
|
||||
}
|
||||
Reference in New Issue
Block a user