diff --git a/bun.lockb b/bun.lockb index 9c4e65df..cc2d4ad1 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/cli.ts b/cli.ts index 3a5cd9b5..dbe29f0f 100644 --- a/cli.ts +++ b/cli.ts @@ -73,6 +73,19 @@ ${chalk.bold("Commands:")} ${chalk.bold("Example:")} ${chalk.bgGray( `bun cli user search admin` )} + ${alignDots( + chalk.blue("connect-openid") + )} Connect an OpenID account to a local account + ${alignDotsSmall( + chalk.green("username") + )} Username of the local account + ${alignDotsSmall(chalk.green("issuerId"))} ID of the OpenID issuer + ${alignDotsSmall( + chalk.green("serverId") + )} ID of the user on the OpenID server + ${chalk.bold("Example:")} ${chalk.bgGray( + `bun cli user connect-openid admin google 123456789` + )} ${alignDots(chalk.blue("note"), 24)} Manage notes ${alignDots(chalk.blue("delete"))} Delete a note ${alignDotsSmall(chalk.green("id"))} ID of the note @@ -403,6 +416,62 @@ switch (command) { break; } + case "connect-openid": { + const username = args[4]; + const issuerId = args[5]; + const serverId = args[6]; + + if (!username || !issuerId || !serverId) { + console.log( + `${chalk.red(`✗`)} Missing username, issuer or ID` + ); + process.exit(1); + } + + const user = await client.user.findFirst({ + where: { + username: username, + }, + }); + + if (!user) { + console.log(`${chalk.red(`✗`)} User not found`); + process.exit(1); + } + + const issuer = config.oidc.providers.find( + p => p.id === issuerId + ); + + if (!issuer) { + console.log(`${chalk.red(`✗`)} Issuer not found`); + process.exit(1); + } + + await client.user.update({ + where: { + id: user.id, + }, + data: { + linkedOpenIdAccounts: { + create: { + issuerId: issuerId, + serverId: serverId, + }, + }, + }, + }); + + console.log( + `${chalk.green( + `✓` + )} Connected OpenID account to user ${chalk.blue( + user.username + )}` + ); + + break; + } default: console.log(`Unknown command ${chalk.blue(command)}`); break; diff --git a/config/config.example.toml b/config/config.example.toml index 8af0ecd9..0d4ae856 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -24,6 +24,18 @@ port = 40007 api_key = "" enabled = true +# Delete this section if you don't want to use custom OAuth providers +# This is an example configuration +# The provider MUST support OpenID Connect with .well-known discovery +# Most notably, GitHub does not support this +[[oidc.providers]] +name = "CPlusPatch ID" +id = "cpluspatch-id" +url = "https://id.cpluspatch.com/application/o/lysand-testing/" +client_id = "XXXXXXXXXXXXXXXX" +client_secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" +icon = "https://cpluspatch.com/images/icons/logo.svg" + [http] base_url = "https://lysand.social" bind = "http://localhost" diff --git a/package.json b/package.json index 62ddf26c..a16ddb2d 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "migrate-dev": "bun prisma migrate dev", "migrate": "bun prisma migrate deploy", "lint": "eslint --config .eslintrc.cjs --ext .ts .", - "prisma": "bun run prisma.ts", + "prisma": "DATABASE_URL=$(bun run prisma.ts) bunx prisma", "generate": "bun prisma generate", "benchmark:timeline": "bun run benchmarks/timelines.ts", "cloc": "cloc . --exclude-dir node_modules", @@ -94,11 +94,13 @@ "linkifyjs": "^4.1.3", "marked": "^9.1.2", "meilisearch": "^0.36.0", + "oauth4webapi": "^2.4.0", "prisma": "^5.6.0", "prisma-redis-middleware": "^4.8.0", "semver": "^7.5.4", "sharp": "^0.33.0-rc.2", "vite": "^5.0.4", + "vite-ssr": "^0.17.1", "vue": "^3.3.9", "vue-router": "^4.2.5", "vue-tsc": "^1.8.24" diff --git a/pages/App.vue b/pages/App.vue index 1e5d5a5f..6f8f7da5 100644 --- a/pages/App.vue +++ b/pages/App.vue @@ -1,6 +1,6 @@