spec(backend): IdentifiableErrorの場合もエラーメッセージが正常に表示されるように (MisskeyIO#463)
This commit is contained in:
parent
82cc3987c1
commit
4eb645403f
@ -523,7 +523,7 @@ export class DriveService {
|
||||
// If usage limit exceeded
|
||||
if (driveCapacity < usage + info.size) {
|
||||
if (isLocalUser) {
|
||||
throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.');
|
||||
throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space in drive.');
|
||||
}
|
||||
await this.expireOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as MiRemoteUser, driveCapacity - info.size);
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||
|
||||
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
|
||||
this.logger.error('Request rejected because prohibited words are included', { user: user.id, note: data });
|
||||
throw new IdentifiableError('057d8d3e-b7ca-4f8b-b38c-dcdcbf34dc30');
|
||||
throw new IdentifiableError('057d8d3e-b7ca-4f8b-b38c-dcdcbf34dc30', 'Notes including prohibited words are not allowed.');
|
||||
}
|
||||
|
||||
const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host);
|
||||
|
@ -108,7 +108,7 @@ export class ReactionService {
|
||||
if (note.userId !== user.id) {
|
||||
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
|
||||
if (blocked) {
|
||||
throw new IdentifiableError('e70412a4-7197-4726-8e74-f3e0deb92aa7');
|
||||
throw new IdentifiableError('e70412a4-7197-4726-8e74-f3e0deb92aa7', 'You are blocked by the user.');
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ export class ReactionService {
|
||||
await this.noteReactionsRepository.insert(record);
|
||||
} else {
|
||||
// 同じリアクションがすでにされていたらエラー
|
||||
throw new IdentifiableError('51c42bb4-931a-456b-bff7-e5a8a70dd298');
|
||||
throw new IdentifiableError('51c42bb4-931a-456b-bff7-e5a8a70dd298', 'You already reacted to this note with the same reaction.');
|
||||
}
|
||||
} else {
|
||||
throw e;
|
||||
@ -288,14 +288,14 @@ export class ReactionService {
|
||||
});
|
||||
|
||||
if (exist == null) {
|
||||
throw new IdentifiableError('60527ec9-b4cb-4a88-a6bd-32d3ad26817d', 'not reacted');
|
||||
throw new IdentifiableError('60527ec9-b4cb-4a88-a6bd-32d3ad26817d', 'You have not reacted to this note.');
|
||||
}
|
||||
|
||||
// Delete reaction
|
||||
const result = await this.noteReactionsRepository.delete(exist.id);
|
||||
|
||||
if (result.affected !== 1) {
|
||||
throw new IdentifiableError('60527ec9-b4cb-4a88-a6bd-32d3ad26817d', 'not reacted');
|
||||
throw new IdentifiableError('60527ec9-b4cb-4a88-a6bd-32d3ad26817d', 'You have not reacted to this note.');
|
||||
}
|
||||
|
||||
// Decrement reactions count
|
||||
|
@ -36,7 +36,7 @@ export class UserAuthService {
|
||||
});
|
||||
|
||||
if (delta === null) {
|
||||
throw new IdentifiableError('7d0a7d85-206c-4d16-8cf3-8af92249a082', 'authentication failed');
|
||||
throw new IdentifiableError('7d0a7d85-206c-4d16-8cf3-8af92249a082', 'Two-factor authentication failed.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,8 +124,8 @@ export class UserFollowingService implements OnModuleInit {
|
||||
await this.userBlockingService.unblock(follower, followee);
|
||||
} else {
|
||||
// それ以外は単純に例外
|
||||
if (blocking) throw new IdentifiableError('710e8fb0-b8c3-4922-be49-d5d93d8e6a6e', 'blocking');
|
||||
if (blocked) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked');
|
||||
if (blocking) throw new IdentifiableError('710e8fb0-b8c3-4922-be49-d5d93d8e6a6e', 'You have blocked this user.');
|
||||
if (blocked) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'You have been blocked by this user.');
|
||||
}
|
||||
|
||||
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
|
||||
@ -538,7 +538,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||
});
|
||||
|
||||
if (!requestExist) {
|
||||
throw new IdentifiableError('17447091-ce07-46dd-b331-c1fd4f15b1e7', 'request not found');
|
||||
throw new IdentifiableError('17447091-ce07-46dd-b331-c1fd4f15b1e7', 'No such follow request.');
|
||||
}
|
||||
|
||||
await this.followRequestsRepository.delete({
|
||||
@ -564,7 +564,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||
});
|
||||
|
||||
if (request == null) {
|
||||
throw new IdentifiableError('8884c2dd-5795-4ac9-b27e-6a01d38190f9', 'No follow request.');
|
||||
throw new IdentifiableError('8884c2dd-5795-4ac9-b27e-6a01d38190f9', 'No such follow request.');
|
||||
}
|
||||
|
||||
await this.insertFollowingDoc(followee, follower, false, request.withReplies);
|
||||
|
@ -107,7 +107,7 @@ export class WebAuthnService {
|
||||
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
|
||||
|
||||
if (!challenge) {
|
||||
throw new IdentifiableError('7dbfb66c-9216-4e2b-9c27-cef2ac8efb84', 'challenge not found');
|
||||
throw new IdentifiableError('7dbfb66c-9216-4e2b-9c27-cef2ac8efb84', 'Unable to find registration challenge. Please try again.');
|
||||
}
|
||||
|
||||
await this.redisClient.del(`webauthn:challenge:${userId}`);
|
||||
@ -125,13 +125,13 @@ export class WebAuthnService {
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to verify registration response', { error });
|
||||
throw new IdentifiableError('5c1446f8-8ca7-4d31-9f39-656afe9c5d87', 'verification failed');
|
||||
throw new IdentifiableError('5c1446f8-8ca7-4d31-9f39-656afe9c5d87', 'Unable to verify registration response. Please try again.');
|
||||
}
|
||||
|
||||
const { verified } = verification;
|
||||
|
||||
if (!verified || !verification.registrationInfo) {
|
||||
throw new IdentifiableError('bb333667-3832-4a80-8bb5-c505be7d710d', 'verification failed');
|
||||
throw new IdentifiableError('bb333667-3832-4a80-8bb5-c505be7d710d', 'Unable to verify registration response. Please try again.');
|
||||
}
|
||||
|
||||
const { registrationInfo } = verification;
|
||||
@ -156,7 +156,7 @@ export class WebAuthnService {
|
||||
});
|
||||
|
||||
if (keys.length === 0) {
|
||||
throw new IdentifiableError('f27fd449-9af4-4841-9249-1f989b9fa4a4', 'no keys found');
|
||||
throw new IdentifiableError('f27fd449-9af4-4841-9249-1f989b9fa4a4', 'You have no registered security keys or passkeys yet.');
|
||||
}
|
||||
|
||||
const authenticationOptions = await generateAuthenticationOptions({
|
||||
@ -178,7 +178,7 @@ export class WebAuthnService {
|
||||
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
|
||||
|
||||
if (!challenge) {
|
||||
throw new IdentifiableError('2d16e51c-007b-4edd-afd2-f7dd02c947f6', 'challenge not found');
|
||||
throw new IdentifiableError('2d16e51c-007b-4edd-afd2-f7dd02c947f6', 'Unable to find authentication challenge. Please try again.');
|
||||
}
|
||||
|
||||
await this.redisClient.del(`webauthn:challenge:${userId}`);
|
||||
@ -189,7 +189,7 @@ export class WebAuthnService {
|
||||
});
|
||||
|
||||
if (!key) {
|
||||
throw new IdentifiableError('36b96a7d-b547-412d-aeed-2d611cdc8cdc', 'unknown key');
|
||||
throw new IdentifiableError('36b96a7d-b547-412d-aeed-2d611cdc8cdc', 'Unable to identify your security key. Please try with another key.');
|
||||
}
|
||||
|
||||
// マイグレーション
|
||||
@ -235,7 +235,7 @@ export class WebAuthnService {
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to verify authentication response', { error });
|
||||
throw new IdentifiableError('b18c89a7-5b5e-4cec-bb5b-0419f332d430', 'verification failed');
|
||||
throw new IdentifiableError('b18c89a7-5b5e-4cec-bb5b-0419f332d430', 'Unable to verify authentication response. Please try again.');
|
||||
}
|
||||
|
||||
const { verified, authenticationInfo } = verification;
|
||||
|
@ -10,9 +10,9 @@ export class IdentifiableError extends Error {
|
||||
public message: string;
|
||||
public id: string;
|
||||
|
||||
constructor(id: string, message?: string) {
|
||||
constructor(id: string, message: string) {
|
||||
super(message);
|
||||
this.message = message ?? '';
|
||||
this.message = message;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,12 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||
id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
|
||||
}));
|
||||
} else {
|
||||
this.send(reply, 500, new ApiError());
|
||||
this.#sendApiError(reply, new ApiError({
|
||||
message: 'Internal error occurred. Please contact us if the error persists.',
|
||||
code: 'INTERNAL_ERROR',
|
||||
id: '5d37dbcb-891e-41ca-a3d6-e690c97775ac',
|
||||
kind: 'server',
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,8 +369,33 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||
|
||||
// API invoking
|
||||
return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => {
|
||||
if (err instanceof ApiError || err instanceof IdentifiableError || err instanceof AuthenticationError) {
|
||||
if (err instanceof ApiError || err instanceof AuthenticationError) {
|
||||
throw err;
|
||||
} else if (err instanceof IdentifiableError) {
|
||||
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
||||
ep: ep.name,
|
||||
ps: data,
|
||||
id: err.id,
|
||||
error: {
|
||||
message: err.message,
|
||||
code: 'INTERNAL_ERROR',
|
||||
stack: err.stack,
|
||||
},
|
||||
});
|
||||
throw new ApiError(
|
||||
{
|
||||
message: err.message,
|
||||
code: 'INTERNAL_ERROR',
|
||||
id: err.id,
|
||||
},
|
||||
{
|
||||
e: {
|
||||
message: err.message,
|
||||
code: err.name,
|
||||
id: err.id,
|
||||
},
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const errId = randomUUID();
|
||||
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
||||
@ -378,13 +408,21 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||
stack: err.stack,
|
||||
},
|
||||
});
|
||||
throw new ApiError(null, {
|
||||
e: {
|
||||
message: err.message,
|
||||
code: err.name,
|
||||
id: errId,
|
||||
throw new ApiError(
|
||||
{
|
||||
message: 'Internal error occurred. Please contact us if the error persists.',
|
||||
code: 'INTERNAL_ERROR',
|
||||
id: '5d37dbcb-891e-41ca-a3d6-e690c97775ac',
|
||||
kind: 'server',
|
||||
},
|
||||
});
|
||||
{
|
||||
e: {
|
||||
message: err.message,
|
||||
code: err.name,
|
||||
id: errId,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -13,15 +13,7 @@ export class ApiError extends Error {
|
||||
public httpStatusCode?: number;
|
||||
public info?: any;
|
||||
|
||||
constructor(err?: E | null | undefined, info?: any | null | undefined) {
|
||||
if (err == null) err = {
|
||||
message: 'Internal error occurred. Please contact us if the error persists.',
|
||||
code: 'INTERNAL_ERROR',
|
||||
id: '5d37dbcb-891e-41ca-a3d6-e690c97775ac',
|
||||
kind: 'server',
|
||||
httpStatusCode: 500,
|
||||
};
|
||||
|
||||
constructor(err: E, info?: any | null | undefined) {
|
||||
super(err.message);
|
||||
this.message = err.message;
|
||||
this.code = err.code;
|
||||
|
Loading…
Reference in New Issue
Block a user