mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
feat(cli): ✨ Add generate-keys CLI command
This commit is contained in:
parent
33f16bb9b1
commit
11bb0a6f49
18
cli/commands/generate-keys.ts
Normal file
18
cli/commands/generate-keys.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import chalk from "chalk";
|
||||||
|
import { User } from "~/classes/database/user";
|
||||||
|
import { BaseCommand } from "~/cli/base";
|
||||||
|
|
||||||
|
export default class GenerateKeys extends BaseCommand<typeof GenerateKeys> {
|
||||||
|
static override args = {};
|
||||||
|
|
||||||
|
static override description = "Generates keys to use in Versia Server";
|
||||||
|
|
||||||
|
static override flags = {};
|
||||||
|
|
||||||
|
public async run(): Promise<void> {
|
||||||
|
const { public_key, private_key } = await User.generateKeys();
|
||||||
|
|
||||||
|
this.log(`Generated public key: ${chalk.gray(public_key)}`);
|
||||||
|
this.log(`Generated private key: ${chalk.gray(private_key)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
cli/index.ts
46
cli/index.ts
|
|
@ -1,37 +1,31 @@
|
||||||
import { configureLoggers } from "@/loggers";
|
import { configureLoggers } from "@/loggers";
|
||||||
import { execute } from "@oclif/core";
|
import { execute } from "@oclif/core";
|
||||||
import EmojiAdd from "./commands/emoji/add.ts";
|
|
||||||
import EmojiDelete from "./commands/emoji/delete.ts";
|
|
||||||
import EmojiImport from "./commands/emoji/import.ts";
|
|
||||||
import EmojiList from "./commands/emoji/list.ts";
|
|
||||||
import FederationInstanceFetch from "./commands/federation/instance/fetch.ts";
|
|
||||||
import FederationUserFetch from "./commands/federation/user/fetch.ts";
|
|
||||||
import FederationUserFinger from "./commands/federation/user/finger.ts";
|
|
||||||
import IndexRebuild from "./commands/index/rebuild.ts";
|
|
||||||
import Start from "./commands/start.ts";
|
import Start from "./commands/start.ts";
|
||||||
import UserCreate from "./commands/user/create.ts";
|
|
||||||
import UserDelete from "./commands/user/delete.ts";
|
|
||||||
import UserList from "./commands/user/list.ts";
|
|
||||||
import UserRefetch from "./commands/user/refetch.ts";
|
|
||||||
import UserReset from "./commands/user/reset.ts";
|
|
||||||
|
|
||||||
await configureLoggers();
|
await configureLoggers();
|
||||||
|
|
||||||
// Use "explicit" oclif strategy to avoid issues with oclif's module resolver and bundling
|
// Use "explicit" oclif strategy to avoid issues with oclif's module resolver and bundling
|
||||||
export const commands = {
|
export const commands = {
|
||||||
"user:list": UserList,
|
"user:list": (await import("./commands/user/list.ts")).default,
|
||||||
"user:delete": UserDelete,
|
"user:delete": (await import("./commands/user/delete.ts")).default,
|
||||||
"user:create": UserCreate,
|
"user:create": (await import("./commands/user/create.ts")).default,
|
||||||
"user:reset": UserReset,
|
"user:reset": (await import("./commands/user/reset.ts")).default,
|
||||||
"user:refetch": UserRefetch,
|
"user:refetch": (await import("./commands/user/refetch.ts")).default,
|
||||||
"emoji:add": EmojiAdd,
|
"emoji:add": (await import("./commands/emoji/add.ts")).default,
|
||||||
"emoji:delete": EmojiDelete,
|
"emoji:delete": (await import("./commands/emoji/delete.ts")).default,
|
||||||
"emoji:list": EmojiList,
|
"emoji:list": (await import("./commands/emoji/list.ts")).default,
|
||||||
"emoji:import": EmojiImport,
|
"emoji:import": (await import("./commands/emoji/import.ts")).default,
|
||||||
"index:rebuild": IndexRebuild,
|
"index:rebuild": (await import("./commands/index/rebuild.ts")).default,
|
||||||
"federation:instance:fetch": FederationInstanceFetch,
|
"federation:instance:fetch": (
|
||||||
"federation:user:finger": FederationUserFinger,
|
await import("./commands/federation/instance/fetch.ts")
|
||||||
"federation:user:fetch": FederationUserFetch,
|
).default,
|
||||||
|
"federation:user:finger": (
|
||||||
|
await import("./commands/federation/user/finger.ts")
|
||||||
|
).default,
|
||||||
|
"federation:user:fetch": (
|
||||||
|
await import("./commands/federation/user/fetch.ts")
|
||||||
|
).default,
|
||||||
|
"generate-keys": (await import("./commands/generate-keys.ts")).default,
|
||||||
start: Start,
|
start: Start,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,8 @@ description = "A Versia Server instance"
|
||||||
# URL to your instance banner
|
# URL to your instance banner
|
||||||
# banner = ""
|
# banner = ""
|
||||||
|
|
||||||
# Used for federation. If left empty or missing, the server will generate one for you.
|
# Used for federation.
|
||||||
|
# Use the "generate-keys" CLI command to generate these keys
|
||||||
[instance.keys]
|
[instance.keys]
|
||||||
public = ""
|
public = ""
|
||||||
private = ""
|
private = ""
|
||||||
|
|
@ -413,10 +414,10 @@ forced = false
|
||||||
# Overriden by the signups.registration setting
|
# Overriden by the signups.registration setting
|
||||||
allow_registration = true
|
allow_registration = true
|
||||||
|
|
||||||
# [plugins.config."@versia/openid".keys]
|
[plugins.config."@versia/openid".keys]
|
||||||
# Run Versia Server with those values missing to generate a new key
|
# Use the "generate-keys" CLI command to generate these keys
|
||||||
# public = ""
|
public = ""
|
||||||
# private = ""
|
private = ""
|
||||||
|
|
||||||
# The provider MUST support OpenID Connect with .well-known discovery
|
# The provider MUST support OpenID Connect with .well-known discovery
|
||||||
# Most notably, GitHub does not support this
|
# Most notably, GitHub does not support this
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Hooks, Plugin } from "@versia/kit";
|
import { Hooks, Plugin } from "@versia/kit";
|
||||||
|
import chalk from "chalk";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import authorizeRoute from "./routes/authorize.ts";
|
import authorizeRoute from "./routes/authorize.ts";
|
||||||
import jwksRoute from "./routes/jwks.ts";
|
import jwksRoute from "./routes/jwks.ts";
|
||||||
|
|
@ -26,10 +27,7 @@ const plugin = new Plugin(
|
||||||
)
|
)
|
||||||
.default([]),
|
.default([]),
|
||||||
keys: z.object({
|
keys: z.object({
|
||||||
public: z
|
public: z.string().transform(async (v) => {
|
||||||
.string()
|
|
||||||
.min(1)
|
|
||||||
.transform(async (v) => {
|
|
||||||
try {
|
try {
|
||||||
return await crypto.subtle.importKey(
|
return await crypto.subtle.importKey(
|
||||||
"spki",
|
"spki",
|
||||||
|
|
@ -40,14 +38,11 @@ const plugin = new Plugin(
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Public key at oidc.keys.public is invalid",
|
`Public key at keys.public is invalid. Run the ${chalk.bold("generate-keys")} command to generate a new keypair`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
private: z
|
private: z.string().transform(async (v) => {
|
||||||
.string()
|
|
||||||
.min(1)
|
|
||||||
.transform(async (v) => {
|
|
||||||
try {
|
try {
|
||||||
return await crypto.subtle.importKey(
|
return await crypto.subtle.importKey(
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
|
|
@ -58,7 +53,7 @@ const plugin = new Plugin(
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Private key at oidc.keys.private is invalid",
|
`Private key at keys.private is invalid. Run the ${chalk.bold("generate-keys")} command to generate a new keypair`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { getLogger } from "@logtape/logtape";
|
import { getLogger } from "@logtape/logtape";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import { User } from "~/classes/database/user";
|
|
||||||
import type { Config } from "~/packages/config-manager";
|
import type { Config } from "~/packages/config-manager";
|
||||||
|
|
||||||
export const checkConfig = async (config: Config) => {
|
export const checkConfig = async (config: Config) => {
|
||||||
|
|
@ -69,15 +68,8 @@ const checkFederationConfig = async (config: Config) => {
|
||||||
const logger = getLogger("server");
|
const logger = getLogger("server");
|
||||||
|
|
||||||
if (!(config.instance.keys.public && config.instance.keys.private)) {
|
if (!(config.instance.keys.public && config.instance.keys.private)) {
|
||||||
logger.fatal`The federation keys are not set in the config`;
|
logger.fatal`The federation keys are not set in the config at instance.keys.public and instance.keys.private`;
|
||||||
logger.fatal`Below are generated keys for you to copy in the config at instance.keys.public and instance.keys.private`;
|
logger.fatal`You can generate a keypair using the CLI command ${chalk.bold("generate-keys")}`;
|
||||||
|
|
||||||
// Generate a key for them
|
|
||||||
const { public_key, private_key } = await User.generateKeys();
|
|
||||||
|
|
||||||
logger.fatal`Generated public key: ${chalk.gray(public_key)}`;
|
|
||||||
logger.fatal`Generated private key: ${chalk.gray(private_key)}`;
|
|
||||||
|
|
||||||
// Hang until Ctrl+C is pressed
|
// Hang until Ctrl+C is pressed
|
||||||
await Bun.sleep(Number.POSITIVE_INFINITY);
|
await Bun.sleep(Number.POSITIVE_INFINITY);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue