diff --git a/flake.lock b/flake.lock deleted file mode 100644 index f8964420ec..0000000000 --- a/flake.lock +++ /dev/null @@ -1,61 +0,0 @@ -{ - "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1766651565, - "narHash": "sha256-QEhk0eXgyIqTpJ/ehZKg9IKS7EtlWxF3N7DXy42zPfU=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "3e2499d5539c16d0d173ba53552a4ff8547f4539", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 80eefa3f6f..0000000000 --- a/flake.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - description = "Development environment for Sharkey"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-utils.url = "github:numtide/flake-utils"; - }; - - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - { - devShells.default = pkgs.mkShell { - buildInputs = with pkgs; [ - nodejs - pnpm_9 - - pkg-config - python3 - makeWrapper - - cairo - pango - pixman - vips - ffmpeg-headless - jemalloc - - ]; - - shellHook = '' - export NODE_ENV=development - export npm_config_nodedir=${pkgs.nodejs} - ''; - - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ - pkgs.ffmpeg-headless - pkgs.jemalloc - pkgs.stdenv.cc.cc - pkgs.cairo - pkgs.pango - pkgs.pixman - pkgs.vips - ]; - - PKG_CONFIG_PATH = "${pkgs.cairo}/lib/pkgconfig:${pkgs.pango}/lib/pkgconfig:${pkgs.pixman}/lib/pkgconfig:${pkgs.vips}/lib/pkgconfig"; - }; - } - ); -} diff --git a/packages/backend/package.json b/packages/backend/package.json index f75a964ac6..bfa32c8612 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -138,7 +138,6 @@ "ip-cidr": "4.0.2", "ipaddr.js": "2.2.0", "is-svg": "6.1.0", - "jose": "^6.1.3", "js-yaml": "4.1.0", "json5": "2.2.3", "jsonld": "8.3.3", diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts index 6c2967706c..be3892e942 100644 --- a/packages/backend/src/config.ts +++ b/packages/backend/src/config.ts @@ -161,17 +161,6 @@ type Source = { customHtml?: { head?: string; } - - oidc: { - name: string; - authEndpoint: string; - tokenEndpoint: string; - clientId: string; - clientSecret: string; - scope: string[]; - autoRegister: boolean; - usernameClaim: string; - } | undefined; }; export type PrivateNetworkSource = string | { network?: string, ports?: number[] }; @@ -350,17 +339,6 @@ export type Config = { } | undefined; pidFile: string; - - oidc: { - name: string; - authEndpoint: string; - tokenEndpoint: string; - clientId: string; - clientSecret: string; - scope: string[]; - autoRegister: boolean; - usernameClaim: string; - } | undefined; filePermissionBits?: string; activityLogging: { @@ -543,7 +521,6 @@ export function loadConfig(loggerService: LoggerService): Config { customHtml: { head: config.customHtml?.head ?? '', }, - oidc: config.oidc, }; } diff --git a/packages/backend/src/server/ServerModule.ts b/packages/backend/src/server/ServerModule.ts index 4e0283ddac..8ff8da380a 100644 --- a/packages/backend/src/server/ServerModule.ts +++ b/packages/backend/src/server/ServerModule.ts @@ -64,7 +64,6 @@ import { ChatRoomChannelService } from './api/stream/channels/chat-room.js'; import { ReversiChannelService } from './api/stream/channels/reversi.js'; import { ReversiGameChannelService } from './api/stream/channels/reversi-game.js'; import { SigninWithPasskeyApiService } from './api/SigninWithPasskeyApiService.js'; -import { OidcApiService } from './api/OidcApiService.js'; @Module({ imports: [ @@ -129,7 +128,6 @@ import { OidcApiService } from './api/OidcApiService.js'; ApiStatusMastodon, ApiTimelineMastodon, ServerUtilityService, - OidcApiService, ], exports: [ ServerService, diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts index c717716342..8900048de0 100644 --- a/packages/backend/src/server/api/ApiServerService.ts +++ b/packages/backend/src/server/api/ApiServerService.ts @@ -19,7 +19,6 @@ import { SignupApiService } from './SignupApiService.js'; import { SigninApiService } from './SigninApiService.js'; import { SigninWithPasskeyApiService } from './SigninWithPasskeyApiService.js'; import { CacheService } from '@/core/CacheService.js'; -import { OidcApiService } from './OidcApiService.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; @Injectable() @@ -45,7 +44,6 @@ export class ApiServerService { private signinApiService: SigninApiService, private signinWithPasskeyApiService: SigninWithPasskeyApiService, private cacheService: CacheService, - private oidcApiService: OidcApiService, ) { //this.createServer = this.createServer.bind(this); } @@ -212,14 +210,6 @@ export class ApiServerService { } }); - fastify.get('/oidc/meta', (request, reply) => this.oidcApiService.meta(request, reply)); - fastify.get<{ - Querystring: { - code?: string; - error?: string; - }; - }>('/oidc/callback', (request, reply) => this.oidcApiService.callback(request, reply)); - // Make sure any unknown path under /api returns HTTP 404 Not Found, // because otherwise ClientServerService will return the base client HTML // page with HTTP 200. diff --git a/packages/backend/src/server/api/OidcApiService.ts b/packages/backend/src/server/api/OidcApiService.ts deleted file mode 100644 index 168efc2956..0000000000 --- a/packages/backend/src/server/api/OidcApiService.ts +++ /dev/null @@ -1,216 +0,0 @@ -/* - * SPDX-FileCopyrightText: skye and other Sharkey contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { Inject, Injectable } from '@nestjs/common'; -import * as jose from 'jose'; -import { IsNull } from 'typeorm'; -import { DI } from '@/di-symbols.js'; -import type { - UsedUsernamesRepository, - UsersRepository, -} from '@/models/_.js'; -import type { Config } from '@/config.js'; -import { getIpHash } from '@/misc/get-ip-hash.js'; -import type { MiLocalUser } from '@/models/User.js'; -import { bindThis } from '@/decorators.js'; -import { MetaService } from '@/core/MetaService.js'; -import { FastifyReplyError } from '@/misc/fastify-reply-error.js'; -import { SignupService } from '@/core/SignupService.js'; -import { HttpRequestService } from '@/core/HttpRequestService.js'; -import { SkRateLimiterService } from '@/server/SkRateLimiterService.js'; -import { SigninService } from './SigninService.js'; -import type { FastifyReply, FastifyRequest } from 'fastify'; - -@Injectable() -export class OidcApiService { - constructor( - @Inject(DI.config) - private config: Config, - - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.usedUsernamesRepository) - private usedUsernamesRepository: UsedUsernamesRepository, - - private rateLimiterService: SkRateLimiterService, - private signinService: SigninService, - private signupService: SignupService, - private metaService: MetaService, - private httpRequestService: HttpRequestService, - ) { - } - - @bindThis - public async meta( - _request: FastifyRequest, - _reply: FastifyReply, - ) { - if (this.config.oidc === undefined) { - return { - enabled: false, - }; - } - const url = new URL(this.config.oidc.authEndpoint); - url.searchParams.append('client_id', this.config.oidc.clientId); - url.searchParams.append('redirect_uri', `${this.config.apiUrl}/oidc/callback`); - url.searchParams.append('response_type', 'code'); - url.searchParams.append('scope', this.config.oidc.scope.join(' ')); - return { - enabled: true, - name: this.config.oidc.name, - url, - }; - } - - @bindThis - public async callback( - request: FastifyRequest<{ - Querystring: { - code?: string; - error?: string; - }; - }>, - reply: FastifyReply, - ) { - reply.header('Access-Control-Allow-Origin', this.config.url); - reply.header('Access-Control-Allow-Credentials', 'true'); - - const instance = await this.metaService.fetch(true); - - const query = request.query; - - function error(status: number, error: { id: string }) { - reply.code(status); - return { error }; - } - - if (query.error !== undefined) { - return error(403, { - id: 'bf721f0c-ed11-4c94-bc0a-84aaf8b7431a', - }); - } - - if (query.code === undefined) { - return error(400, { - id: '797c0ae2-2eb9-402d-a2d6-090b5f3f3686', - }); - } - - if (this.config.oidc === undefined) { - return error(403, { - id: '726c5012-eec4-49c8-b613-74fb23c2bdce', - }); - } - - try { - // not more than 1 attempt per second and not more than 10 attempts per hour - await this.rateLimiterService.limit({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(request.ip)); - } catch (err) { - reply.code(429); - return { - error: { - message: 'Too many failed attempts to sign in. Try again later.', - code: 'TOO_MANY_AUTHENTICATION_FAILURES', - id: '22d05606-fbcf-421a-a2db-b32610dcfd1b', - }, - }; - } - - const tokenResponse: { id_token: string } | { error: string } = await (await this.httpRequestService.send(this.config.oidc.tokenEndpoint, { - body: new URLSearchParams({ - code: query.code, - client_id: this.config.oidc.clientId, - client_secret: this.config.oidc.clientSecret, - grant_type: 'authorization_code', - redirect_uri: `${this.config.apiUrl}/oidc/callback`, - }).toString(), - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - method: 'POST', - })).json() as { id_token: string } | { error: string }; - - if ('error' in tokenResponse) { - return error(403, { - id: 'afae6924-7744-4efb-aed1-cfda2ddd8c43', - }); - } - - const token = jose.decodeJwt>(tokenResponse.id_token); - - const username = token[this.config.oidc.usernameClaim]; - - if (username === undefined) { - return error(400, { - id: '3b02c880-cd46-4886-9cda-325529340226', - }); - } - - // Fetch user - let user = await this.usersRepository.findOneBy({ - usernameLower: username.toLowerCase(), - host: IsNull(), - }) as MiLocalUser; - - if (user == null) { - if (this.config.oidc.autoRegister) { - try { - if (await this.usedUsernamesRepository.exists({ where: { username: username.toLowerCase() } })) { - throw new FastifyReplyError(400, 'USED_USERNAME'); - } - const { account } = await this.signupService.signup({ - username, - }); - user = account as MiLocalUser; - } catch (err) { - throw new FastifyReplyError(400, typeof err === 'string' ? err : (err as Error).toString()); - } - } else { - return error(404, { - id: '6cc579cc-885d-43d8-95c2-b8c7fc963280', - }); - } - } - - if (user.isSuspended) { - return error(403, { - id: 'e03a5f46-d309-4865-9b69-56282d94e1eb', - }); - } - - if (!user.approved && instance.approvalRequiredForSignup) { - reply.code(403); - return { - error: { - message: 'The account has not been approved by an admin yet. Try again later.', - code: 'NOT_APPROVED', - id: '22d05606-fbcf-421a-a2db-b32241faft1b', - }, - }; - } - - if (!instance.approvalRequiredForSignup && !user.approved) this.usersRepository.update(user.id, { approved: true }); - - const resp = this.signinService.signin(request, reply, user); - reply.type('text/html'); - return ` - - - Please wait... - - - Please wait... - - - `; - } -} diff --git a/packages/frontend/src/components/MkSignin.input.vue b/packages/frontend/src/components/MkSignin.input.vue index cafb40224f..aacd1eae2a 100644 --- a/packages/frontend/src/components/MkSignin.input.vue +++ b/packages/frontend/src/components/MkSignin.input.vue @@ -30,8 +30,6 @@ SPDX-License-Identifier: AGPL-3.0-only - -
@@ -50,29 +48,17 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.signinWithPasskey }} - - -
-

{{ i18n.ts.or }}

-
-
- - Sign in with {{ oidcName }} - -
-