@atproto/ozone
Version:
Backend service for moderating the Bluesky network.
269 lines • 9.51 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppContext = void 0;
const node_assert_1 = __importDefault(require("node:assert"));
const plc = __importStar(require("@did-plc/lib"));
const api_1 = require("@atproto/api");
const crypto_1 = require("@atproto/crypto");
const identity_1 = require("@atproto/identity");
const xrpc_server_1 = require("@atproto/xrpc-server");
const auth_verifier_1 = require("./auth-verifier");
const background_1 = require("./background");
const template_1 = require("./communication-service/template");
const daemon_1 = require("./daemon");
const blob_diverter_1 = require("./daemon/blob-diverter");
const db_1 = require("./db");
const mod_service_1 = require("./mod-service");
const service_1 = require("./safelink/service");
const sequencer_1 = require("./sequencer/sequencer");
const service_2 = require("./set/service");
const service_3 = require("./setting/service");
const team_1 = require("./team");
const util_1 = require("./util");
const issuer_1 = require("./verification/issuer");
const service_4 = require("./verification/service");
class AppContext {
constructor(opts, secrets) {
Object.defineProperty(this, "opts", {
enumerable: true,
configurable: true,
writable: true,
value: opts
});
Object.defineProperty(this, "secrets", {
enumerable: true,
configurable: true,
writable: true,
value: secrets
});
}
static async fromConfig(cfg, secrets, overrides) {
const db = new db_1.Database({
url: cfg.db.postgresUrl,
schema: cfg.db.postgresSchema,
poolSize: cfg.db.poolSize,
poolMaxUses: cfg.db.poolMaxUses,
poolIdleTimeoutMs: cfg.db.poolIdleTimeoutMs,
});
const signingKey = await crypto_1.Secp256k1Keypair.import(secrets.signingKeyHex);
const signingKeyId = await (0, util_1.getSigningKeyId)(db, signingKey.did());
const appviewAgent = new api_1.AtpAgent({ service: cfg.appview.url });
const pdsAgent = cfg.pds
? new api_1.AtpAgent({ service: cfg.pds.url })
: undefined;
const chatAgent = cfg.chat
? new api_1.AtpAgent({ service: cfg.chat.url })
: undefined;
const didCache = new identity_1.MemoryCache(cfg.identity.cacheStaleTTL, cfg.identity.cacheMaxTTL);
const idResolver = new identity_1.IdResolver({
plcUrl: cfg.identity.plcUrl,
didCache,
});
const createAuthHeaders = (aud, lxm) => (0, xrpc_server_1.createServiceAuthHeaders)({
iss: `${cfg.service.did}#atproto_labeler`,
aud,
lxm,
keypair: signingKey,
});
const backgroundQueue = new background_1.BackgroundQueue(db);
const blobDiverter = cfg.blobDivert
? new blob_diverter_1.BlobDiverter(db, {
idResolver,
serviceConfig: cfg.blobDivert,
})
: undefined;
const eventPusher = new daemon_1.EventPusher(db, createAuthHeaders, {
appview: cfg.appview.pushEvents ? cfg.appview : undefined,
pds: cfg.pds ?? undefined,
});
const modService = mod_service_1.ModerationService.creator(signingKey, signingKeyId, cfg, backgroundQueue, idResolver, eventPusher, appviewAgent, createAuthHeaders, overrides?.imgInvalidator);
const communicationTemplateService = template_1.CommunicationTemplateService.creator();
const safelinkRuleService = service_1.SafelinkRuleService.creator();
const teamService = team_1.TeamService.creator(appviewAgent, cfg.appview.did, createAuthHeaders);
const setService = service_2.SetService.creator();
const settingService = service_3.SettingService.creator();
const verificationService = service_4.VerificationService.creator();
const verificationIssuer = issuer_1.VerificationIssuer.creator();
const sequencer = new sequencer_1.Sequencer(modService(db));
const authVerifier = new auth_verifier_1.AuthVerifier(idResolver, {
serviceDid: cfg.service.did,
adminPassword: secrets.adminPassword,
teamService: teamService(db),
});
return new AppContext({
db,
cfg,
modService,
communicationTemplateService,
safelinkRuleService,
teamService,
setService,
settingService,
appviewAgent,
pdsAgent,
chatAgent,
signingKey,
signingKeyId,
didCache,
idResolver,
backgroundQueue,
sequencer,
authVerifier,
blobDiverter,
verificationService,
verificationIssuer,
...(overrides ?? {}),
}, secrets);
}
assignPort(port) {
(0, node_assert_1.default)(!this.cfg.service.port || this.cfg.service.port === port, 'Conflicting port in config');
this.opts.cfg.service.port = port;
}
get db() {
return this.opts.db;
}
get cfg() {
return this.opts.cfg;
}
get modService() {
return this.opts.modService;
}
get blobDiverter() {
return this.opts.blobDiverter;
}
get communicationTemplateService() {
return this.opts.communicationTemplateService;
}
get safelinkRuleService() {
return this.opts.safelinkRuleService;
}
get teamService() {
return this.opts.teamService;
}
get setService() {
return this.opts.setService;
}
get settingService() {
return this.opts.settingService;
}
get verificationService() {
return this.opts.verificationService;
}
get verificationIssuer() {
return this.opts.verificationIssuer;
}
get appviewAgent() {
return this.opts.appviewAgent;
}
get pdsAgent() {
return this.opts.pdsAgent;
}
get chatAgent() {
return this.opts.chatAgent;
}
get signingKey() {
return this.opts.signingKey;
}
get signingKeyId() {
return this.opts.signingKeyId;
}
get plcClient() {
return new plc.Client(this.cfg.identity.plcUrl);
}
get didCache() {
return this.opts.didCache;
}
get idResolver() {
return this.opts.idResolver;
}
get backgroundQueue() {
return this.opts.backgroundQueue;
}
get sequencer() {
return this.opts.sequencer;
}
get authVerifier() {
return this.opts.authVerifier;
}
async serviceAuthHeaders(aud, lxm) {
const iss = `${this.cfg.service.did}#atproto_labeler`;
return (0, xrpc_server_1.createServiceAuthHeaders)({
iss,
aud,
lxm,
keypair: this.signingKey,
});
}
async pdsAuth(lxm) {
if (!this.cfg.pds) {
return undefined;
}
return this.serviceAuthHeaders(this.cfg.pds.did, lxm);
}
async appviewAuth(lxm) {
return this.serviceAuthHeaders(this.cfg.appview.did, lxm);
}
async chatAuth(lxm) {
if (!this.cfg.chat) {
throw new Error('No chat service configured');
}
return this.serviceAuthHeaders(this.cfg.chat.did, lxm);
}
devOverride(overrides) {
this.opts = {
...this.opts,
...overrides,
};
}
reqLabelers(req) {
const val = req.header(util_1.LABELER_HEADER_NAME);
let parsed;
try {
parsed = (0, util_1.parseLabelerHeader)(val, this.cfg.service.did);
}
catch (err) {
parsed = null;
}
if (!parsed)
return (0, util_1.defaultLabelerHeader)([]);
return parsed;
}
}
exports.AppContext = AppContext;
//# sourceMappingURL=context.js.map