mirror of
https://github.com/outline/outline.git
synced 2026-01-14 07:00:12 -06:00
* chore: Add script to reset encrypted data * Update server/models/WebhookSubscription.ts Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * Update server/scripts/reset-encrypted-data.ts Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> * Add confirmation --------- Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
118 lines
3.0 KiB
TypeScript
118 lines
3.0 KiB
TypeScript
import "./bootstrap";
|
|
import * as readline from "readline";
|
|
import { Transaction } from "sequelize";
|
|
|
|
import {
|
|
OAuthClient,
|
|
User,
|
|
UserAuthentication,
|
|
WebhookSubscription,
|
|
} from "@server/models";
|
|
|
|
import { sequelize } from "@server/storage/database";
|
|
|
|
// Helper function to prompt user for input
|
|
function askQuestion(question: string): Promise<string> {
|
|
const rl = readline.createInterface({
|
|
input: process.stdin,
|
|
output: process.stdout,
|
|
});
|
|
|
|
return new Promise((resolve) => {
|
|
rl.question(question, (answer) => {
|
|
rl.close();
|
|
resolve(answer.trim().toLowerCase());
|
|
});
|
|
});
|
|
}
|
|
|
|
// Helper function to pause and wait for user confirmation
|
|
async function waitForConfirmation(message: string): Promise<boolean> {
|
|
const answer = await askQuestion(`${message} (y/N): `);
|
|
return answer === "y" || answer === "yes";
|
|
}
|
|
|
|
export default async function main() {
|
|
console.log("🔐 Reset Encrypted Data Script");
|
|
console.log("This script will:");
|
|
console.log("- Delete all user authentication tokens");
|
|
console.log("- Rotate webhook signing secrets");
|
|
console.log("- Rotate OAuth client secrets");
|
|
console.log("- Rotate JWT secrets for all users (logging them out)");
|
|
console.log("");
|
|
|
|
const shouldContinue = await waitForConfirmation(
|
|
"⚠️ This will log out all users and invalidate tokens. Continue?"
|
|
);
|
|
if (!shouldContinue) {
|
|
console.log("❌ Operation cancelled.");
|
|
process.exit(0);
|
|
}
|
|
|
|
await sequelize.transaction(async (transaction) => {
|
|
await UserAuthentication.destroy({
|
|
where: {},
|
|
transaction,
|
|
});
|
|
|
|
const webhooks = await WebhookSubscription.findAll({
|
|
lock: Transaction.LOCK.UPDATE,
|
|
transaction,
|
|
});
|
|
|
|
for (const webhook of webhooks) {
|
|
try {
|
|
webhook.rotateSecret();
|
|
await webhook.save({ transaction });
|
|
} catch (err) {
|
|
console.error(
|
|
`Failed to rotate webhook signing secret for webhook ${webhook.id}:`,
|
|
err
|
|
);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const oauthClients = await OAuthClient.findAll({
|
|
lock: Transaction.LOCK.UPDATE,
|
|
transaction,
|
|
});
|
|
|
|
for (const client of oauthClients) {
|
|
try {
|
|
client.rotateClientSecret();
|
|
await client.save({ transaction });
|
|
} catch (err) {
|
|
console.error(
|
|
`Failed to rotate OAuth client secret for client ${client.id}:`,
|
|
err
|
|
);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const users = await User.findAll({
|
|
lock: Transaction.LOCK.UPDATE,
|
|
transaction,
|
|
});
|
|
|
|
for (const user of users) {
|
|
try {
|
|
await user.rotateJwtSecret({ transaction });
|
|
} catch (err) {
|
|
console.error(`Failed to rotate JWT secret for user ${user.id}:`, err);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
console.log(`Reset encrypted data, logged out ${users.length} users`);
|
|
});
|
|
|
|
process.exit(0);
|
|
}
|
|
|
|
// In the test suite we import the script rather than run via node CLI
|
|
if (process.env.NODE_ENV !== "test") {
|
|
void main();
|
|
}
|