summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/api/endpoints/admin/captcha/save.ts
blob: 98ec278ebefe56eb41cea0d6654d01126ad6d1ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * SPDX-FileCopyrightText: syuilo and misskey-project
 * SPDX-License-Identifier: AGPL-3.0-only
 */

import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { captchaErrorCodes, CaptchaService, supportedCaptchaProviders } from '@/core/CaptchaService.js';
import { ApiError } from '@/server/api/error.js';

export const meta = {
	tags: ['admin', 'captcha'],

	requireCredential: true,
	requireAdmin: true,

	// 実態はmetaの更新であるため
	kind: 'write:admin:meta',

	errors: {
		invalidProvider: {
			message: 'Invalid provider.',
			code: 'INVALID_PROVIDER',
			id: '14bf7ae1-80cc-4363-acb2-4fd61d086af0',
			httpStatusCode: 400,
		},
		invalidParameters: {
			message: 'Invalid parameters.',
			code: 'INVALID_PARAMETERS',
			id: '26654194-410e-44e2-b42e-460ff6f92476',
			httpStatusCode: 400,
		},
		noResponseProvided: {
			message: 'No response provided.',
			code: 'NO_RESPONSE_PROVIDED',
			id: '40acbba8-0937-41fb-bb3f-474514d40afe',
			httpStatusCode: 400,
		},
		requestFailed: {
			message: 'Request failed.',
			code: 'REQUEST_FAILED',
			id: '0f4fe2f1-2c15-4d6e-b714-efbfcde231cd',
			httpStatusCode: 500,
		},
		verificationFailed: {
			message: 'Verification failed.',
			code: 'VERIFICATION_FAILED',
			id: 'c41c067f-24f3-4150-84b2-b5a3ae8c2214',
			httpStatusCode: 400,
		},
		unknown: {
			message: 'unknown',
			code: 'UNKNOWN',
			id: 'f868d509-e257-42a9-99c1-42614b031a97',
			httpStatusCode: 500,
		},
	},
} as const;

export const paramDef = {
	type: 'object',
	properties: {
		provider: {
			type: 'string',
			enum: supportedCaptchaProviders,
		},
		captchaResult: {
			type: 'string', nullable: true,
		},
		sitekey: {
			type: 'string', nullable: true,
		},
		secret: {
			type: 'string', nullable: true,
		},
		instanceUrl: {
			type: 'string', nullable: true,
		},
	},
	required: ['provider'],
} as const;

@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
	constructor(
		private captchaService: CaptchaService,
	) {
		super(meta, paramDef, async (ps) => {
			const result = await this.captchaService.save(ps.provider, {
				sitekey: ps.sitekey,
				secret: ps.secret,
				instanceUrl: ps.instanceUrl,
				captchaResult: ps.captchaResult,
			});

			if (!result.success) {
				switch (result.error.code) {
					case captchaErrorCodes.invalidProvider:
						throw new ApiError({
							...meta.errors.invalidProvider,
							message: result.error.message,
						});
					case captchaErrorCodes.invalidParameters:
						throw new ApiError({
							...meta.errors.invalidParameters,
							message: result.error.message,
						});
					case captchaErrorCodes.noResponseProvided:
						throw new ApiError({
							...meta.errors.noResponseProvided,
							message: result.error.message,
						});
					case captchaErrorCodes.requestFailed:
						throw new ApiError({
							...meta.errors.requestFailed,
							message: result.error.message,
						});
					case captchaErrorCodes.verificationFailed:
						throw new ApiError({
							...meta.errors.verificationFailed,
							message: result.error.message,
						});
					default:
						throw new ApiError(meta.errors.unknown);
				}
			}
		});
	}
}