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 usage limit exceeded
|
||||||
if (driveCapacity < usage + info.size) {
|
if (driveCapacity < usage + info.size) {
|
||||||
if (isLocalUser) {
|
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);
|
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)) {
|
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 });
|
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);
|
const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host);
|
||||||
|
|
|
@ -108,7 +108,7 @@ export class ReactionService {
|
||||||
if (note.userId !== user.id) {
|
if (note.userId !== user.id) {
|
||||||
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
|
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
|
||||||
if (blocked) {
|
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);
|
await this.noteReactionsRepository.insert(record);
|
||||||
} else {
|
} 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 {
|
} else {
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -288,14 +288,14 @@ export class ReactionService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (exist == null) {
|
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
|
// Delete reaction
|
||||||
const result = await this.noteReactionsRepository.delete(exist.id);
|
const result = await this.noteReactionsRepository.delete(exist.id);
|
||||||
|
|
||||||
if (result.affected !== 1) {
|
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
|
// Decrement reactions count
|
||||||
|
|
|
@ -36,7 +36,7 @@ export class UserAuthService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (delta === null) {
|
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);
|
await this.userBlockingService.unblock(follower, followee);
|
||||||
} else {
|
} else {
|
||||||
// それ以外は単純に例外
|
// それ以外は単純に例外
|
||||||
if (blocking) throw new IdentifiableError('710e8fb0-b8c3-4922-be49-d5d93d8e6a6e', 'blocking');
|
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', 'blocked');
|
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 });
|
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
|
||||||
|
@ -538,7 +538,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!requestExist) {
|
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({
|
await this.followRequestsRepository.delete({
|
||||||
|
@ -564,7 +564,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (request == null) {
|
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);
|
await this.insertFollowingDoc(followee, follower, false, request.withReplies);
|
||||||
|
|
|
@ -107,7 +107,7 @@ export class WebAuthnService {
|
||||||
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
|
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
|
||||||
|
|
||||||
if (!challenge) {
|
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}`);
|
await this.redisClient.del(`webauthn:challenge:${userId}`);
|
||||||
|
@ -125,13 +125,13 @@ export class WebAuthnService {
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error('Failed to verify registration response', { 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;
|
const { verified } = verification;
|
||||||
|
|
||||||
if (!verified || !verification.registrationInfo) {
|
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;
|
const { registrationInfo } = verification;
|
||||||
|
@ -156,7 +156,7 @@ export class WebAuthnService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (keys.length === 0) {
|
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({
|
const authenticationOptions = await generateAuthenticationOptions({
|
||||||
|
@ -178,7 +178,7 @@ export class WebAuthnService {
|
||||||
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
|
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
|
||||||
|
|
||||||
if (!challenge) {
|
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}`);
|
await this.redisClient.del(`webauthn:challenge:${userId}`);
|
||||||
|
@ -189,7 +189,7 @@ export class WebAuthnService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!key) {
|
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) {
|
} catch (error) {
|
||||||
this.logger.error('Failed to verify authentication response', { 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;
|
const { verified, authenticationInfo } = verification;
|
||||||
|
|
|
@ -10,9 +10,9 @@ export class IdentifiableError extends Error {
|
||||||
public message: string;
|
public message: string;
|
||||||
public id: string;
|
public id: string;
|
||||||
|
|
||||||
constructor(id: string, message?: string) {
|
constructor(id: string, message: string) {
|
||||||
super(message);
|
super(message);
|
||||||
this.message = message ?? '';
|
this.message = message;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,12 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
|
id: 'b0a7f5f8-dc2f-4171-b91f-de88ad238e14',
|
||||||
}));
|
}));
|
||||||
} else {
|
} 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
|
// API invoking
|
||||||
return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => {
|
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;
|
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 {
|
} else {
|
||||||
const errId = randomUUID();
|
const errId = randomUUID();
|
||||||
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
||||||
|
@ -378,13 +408,21 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
stack: err.stack,
|
stack: err.stack,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
throw new ApiError(null, {
|
throw new ApiError(
|
||||||
e: {
|
{
|
||||||
message: err.message,
|
message: 'Internal error occurred. Please contact us if the error persists.',
|
||||||
code: err.name,
|
code: 'INTERNAL_ERROR',
|
||||||
id: errId,
|
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 httpStatusCode?: number;
|
||||||
public info?: any;
|
public info?: any;
|
||||||
|
|
||||||
constructor(err?: E | null | undefined, info?: any | null | undefined) {
|
constructor(err: E, 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,
|
|
||||||
};
|
|
||||||
|
|
||||||
super(err.message);
|
super(err.message);
|
||||||
this.message = err.message;
|
this.message = err.message;
|
||||||
this.code = err.code;
|
this.code = err.code;
|
||||||
|
|
Loading…
Reference in New Issue