UNPKG

@m-ld/gateway

Version:

m-ld gateway for services

86 lines 9.12 kB
import { Server as SocketIoServer } from 'socket.io'; import { IoRemotesService } from '@m-ld/m-ld/ext/socket.io-server'; import { JwtAuthorization, KeyAuthorization } from '../server/Authorization.js'; import { AccountOwnedId, as, asUuid, validate } from '../lib/index.js'; import { BadRequestError, ForbiddenError, InternalServerError, NotFoundError, toHttpError } from '../http/errors.js'; import LOG from 'loglevel'; import { Account } from '../server/index.js'; const asHandshakeAuth = as.object({ user: AccountOwnedId.asComponentId.optional(), key: as.string(), jwt: as.string() }); const asHandshakeQuery = as.object({ '@domain': as.string().domain().required() }).unknown(); export class IoService extends IoRemotesService { constructor(gateway, server) { const io = new SocketIoServer(server, { cors: { origin: '*', methods: ['GET', 'POST'] } }); super(io.sockets); this.resolveLive = new Map; // Attach authorisation io.use(async (socket, next) => { try { const { user, key, jwt } = validate(socket.handshake.auth, asHandshakeAuth); const { '@domain': domainName } = validate(socket.handshake.query, asHandshakeQuery); if (!domainName.endsWith(gateway.domainName)) return next(new BadRequestError('Bad gateway')); // The gateway is connecting to a domain: its own, or a subdomain if (key === gateway.me.authKey.toString()) return next(); const sdId = AccountOwnedId.fromDomain(domainName).validate(); const access = { id: sdId, forWrite: 'Subdomain' }; const remotesAuth = await Account.getDetails(gateway.domain, sdId.account, 'remotesAuth'); if (!user && !key && !jwt) { validate(sdId.name, asUuid); // Anonymous messaging requires UUID subdomain if (!remotesAuth.includes('anon')) return next(new ForbiddenError('Anonymous messaging unavailable')); } else { if (user && key) { // key authentication is the default if nothing else is specified if (remotesAuth.length && !remotesAuth.includes('key')) return next(new ForbiddenError('Key-authenticated messaging unavailable')); await new KeyAuthorization(user, key).verifyUser(gateway, access); } else if (jwt) { if (!remotesAuth.includes('jwt')) return next(new ForbiddenError('JWT-authenticated messaging unavailable')); await new JwtAuthorization(jwt).verifyUser(gateway, access); } else { return next(new ForbiddenError('Unrecognised authentication')); } // Ensure named subdomain is in the cache and live if (!gateway.hasClonedSubdomain(sdId)) { const [sdc] = await Promise.all([ gateway.getSubdomain(sdId), new Promise(resolve => this.resolveLive.set(sdId.toDomain(), resolve)) ]); if (sdc == null) return next(new NotFoundError); } } LOG.debug('IO authorised for', user || 'anonymous', 'in', domainName); return next(); } catch (e) { const httpError = toHttpError(e); if (httpError instanceof InternalServerError) LOG.error('IO authorisation failed for', socket.handshake, e); return next(httpError); } }); } async getPresent(domain) { const present = await super.getPresent(domain); if (present.length > 0) { this.resolveLive.get(domain)?.(); this.resolveLive.delete(domain); } return present; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSW9TZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NvY2tldC5pby9Jb1NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sSUFBSSxjQUFjLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDaEYsT0FBTyxFQUFFLGNBQWMsRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZFLE9BQU8sRUFDTCxlQUFlLEVBQUUsY0FBYyxFQUFFLG1CQUFtQixFQUFFLGFBQWEsRUFBRSxXQUFXLEVBQ2pGLE1BQU0sbUJBQW1CLENBQUM7QUFDM0IsT0FBTyxHQUFHLE1BQU0sVUFBVSxDQUFDO0FBQzNCLE9BQU8sRUFBRSxPQUFPLEVBQVcsTUFBTSxvQkFBb0IsQ0FBQztBQUd0RCxNQUFNLGVBQWUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDO0lBQ2hDLElBQUksRUFBRSxjQUFjLENBQUMsYUFBYSxDQUFDLFFBQVEsRUFBRTtJQUM3QyxHQUFHLEVBQUUsRUFBRSxDQUFDLE1BQU0sRUFBRTtJQUNoQixHQUFHLEVBQUUsRUFBRSxDQUFDLE1BQU0sRUFBRTtDQUNqQixDQUFDLENBQUM7QUFDSCxNQUFNLGdCQUFnQixHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUM7SUFDakMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDM0MsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO0FBRWIsTUFBTSxPQUFPLFNBQVUsU0FBUSxnQkFBZ0I7SUFHN0MsWUFBWSxPQUFnQixFQUFFLE1BQWM7UUFDMUMsTUFBTSxFQUFFLEdBQUcs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