@atproto/ozone
Version:
Backend service for moderating the Bluesky network.
66 lines • 3.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
const xrpc_server_1 = require("@atproto/xrpc-server");
const subject_1 = require("../../mod-service/subject");
const tag_service_1 = require("../../tag-service");
const util_1 = require("../../tag-service/util");
const util_2 = require("../util");
function default_1(server, ctx) {
server.com.atproto.moderation.createReport({
auth: ctx.authVerifier.standard,
handler: async ({ input, auth }) => {
const requester = 'iss' in auth.credentials ? auth.credentials.iss : ctx.cfg.service.did;
const { reasonType, reason, modTool } = input.body;
const subject = (0, subject_1.subjectFromInput)(input.body.subject);
// If the report is an appeal, the requester must be the author of the subject
if ((0, util_2.isAppealReport)(reasonType) && requester !== subject.did) {
throw new xrpc_server_1.ForbiddenError('You cannot appeal this report');
}
const db = ctx.db;
await Promise.all([
assertValidReporter(ctx.modService(db), reasonType, requester),
ctx.moderationServiceProfile().validateReasonType(reasonType),
]);
const report = await db.transaction(async (dbTxn) => {
const moderationTxn = ctx.modService(dbTxn);
const { event: reportEvent, subjectStatus } = await moderationTxn.report({
reason,
subject,
reasonType,
reportedBy: requester || ctx.cfg.service.did,
modTool,
});
const tagService = new tag_service_1.TagService(subject, subjectStatus, ctx.cfg.service.did, moderationTxn);
await tagService.evaluateForSubject([(0, util_1.getTagForReport)(reasonType)]);
return reportEvent;
});
const body = ctx.modService(db).views.formatReport(report);
return {
encoding: 'application/json',
body,
};
},
});
}
const assertValidReporter = async (modService, reasonType, did) => {
const reporterStatus = await modService.getCurrentStatus({ did });
// If we don't have a mod status for the reporter, no need to do further checks
if (!reporterStatus.length) {
return;
}
// For appeals, we just need to make sure that the account does not have pending appeal
if ((0, util_2.isAppealReport)(reasonType)) {
if (reporterStatus[0]?.appealed) {
throw new xrpc_server_1.ForbiddenError('Awaiting decision on previous appeal', 'AlreadyAppealed');
}
return;
}
// For non appeals, we need to make sure the reporter account is not already in takendown status
// This is necessary because we allow takendown accounts call createReport but that's only meant for appeals
// and we need to make sure takendown accounts don't abuse this endpoint
if (reporterStatus[0]?.takendown) {
throw new xrpc_server_1.ForbiddenError('Report not accepted from takendown account', 'AccountTakedown');
}
};
//# sourceMappingURL=createReport.js.map