var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { GrantAuthorization } from './grant-authorization.js';
import { PermissionsConditionPublication } from '../types/permissions-types.js';
import { DwnError, DwnErrorCode } from './dwn-error.js';
export class RecordsGrantAuthorization {
    /**
     * Authorizes the given RecordsWrite in the scope of the DID given.
     */
    static authorizeWrite(tenant, incomingMessage, author, messageStore) {
        return __awaiter(this, void 0, void 0, function* () {
            const permissionsGrantMessage = yield GrantAuthorization.authorizeGenericMessage(tenant, incomingMessage, author, incomingMessage.signaturePayload.permissionsGrantId, messageStore);
            RecordsGrantAuthorization.verifyScope(incomingMessage, permissionsGrantMessage);
            RecordsGrantAuthorization.verifyConditions(incomingMessage, permissionsGrantMessage);
        });
    }
    /**
     * Authorizes the scope of a PermissionsGrant for RecordsRead.
     */
    static authorizeRead(tenant, incomingMessage, newestRecordsWrite, author, messageStore) {
        return __awaiter(this, void 0, void 0, function* () {
            const permissionsGrantMessage = yield GrantAuthorization.authorizeGenericMessage(tenant, incomingMessage, author, incomingMessage.signaturePayload.permissionsGrantId, messageStore);
            RecordsGrantAuthorization.verifyScope(newestRecordsWrite, permissionsGrantMessage);
        });
    }
    /**
     * @param recordsWrite The source of the record being authorized. If the incoming message is a write,
     *                     then this is the incoming RecordsWrite. Otherwise, it is the newest existing RecordsWrite.
     */
    static verifyScope(recordsWrite, permissionsGrantMessage) {
        const grantScope = permissionsGrantMessage.descriptor.scope;
        if (RecordsGrantAuthorization.isUnrestrictedScope(grantScope)) {
            // scope has no restrictions beyond interface and method. Message is authorized to access any record.
            return;
        }
        else if (recordsWrite.message.descriptor.protocol !== undefined) {
            // authorization of protocol records must have grants that explicitly include the protocol
            RecordsGrantAuthorization.authorizeProtocolRecord(recordsWrite, grantScope);
        }
        else {
            RecordsGrantAuthorization.authorizeFlatRecord(recordsWrite, grantScope);
        }
    }
    /**
     * Authorizes a grant scope for a protocol record
     */
    static authorizeProtocolRecord(recordsWrite, grantScope) {
        // Protocol records must have grants specifying the protocol
        if (grantScope.protocol === undefined) {
            throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeNotProtocol, 'Grant for protocol record must specify protocol in its scope');
        }
        // The record's protocol must match the protocol specified in the record
        if (grantScope.protocol !== recordsWrite.message.descriptor.protocol) {
            throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolMismatch, `Grant scope specifies different protocol than what appears in the record`);
        }
        // If grant specifies either contextId, check that record is that context
        if (grantScope.contextId !== undefined && grantScope.contextId !== recordsWrite.message.contextId) {
            throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeContextIdMismatch, `Grant scope specifies different contextId than what appears in the record`);
        }
        // If grant specifies protocolPath, check that record is at that protocolPath
        if (grantScope.protocolPath !== undefined && grantScope.protocolPath !== recordsWrite.message.descriptor.protocolPath) {
            throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeProtocolPathMismatch, `Grant scope specifies different protocolPath than what appears in the record`);
        }
    }
    /**
     * Authorizes a grant scope for a non-protocol record
     */
    static authorizeFlatRecord(recordsWrite, grantScope) {
        if (grantScope.schema !== undefined) {
            if (grantScope.schema !== recordsWrite.message.descriptor.schema) {
                throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationScopeSchema, `Record does not have schema in PermissionsGrant scope with schema '${grantScope.schema}'`);
            }
        }
    }
    /**
     * Verifies grant `conditions`.
     * Currently the only condition is `published` which only applies to RecordsWrites
     */
    static verifyConditions(incomingMessage, permissionsGrantMessage) {
        const conditions = permissionsGrantMessage.descriptor.conditions;
        // If conditions require publication, RecordsWrite must have `published` === true
        if ((conditions === null || conditions === void 0 ? void 0 : conditions.publication) === PermissionsConditionPublication.Required && !incomingMessage.message.descriptor.published) {
            throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationRequired, 'PermissionsGrant requires message to be published');
        }
        // if conditions prohibit publication, RecordsWrite must have published === false or undefined
        if ((conditions === null || conditions === void 0 ? void 0 : conditions.publication) === PermissionsConditionPublication.Prohibited && incomingMessage.message.descriptor.published) {
            throw new DwnError(DwnErrorCode.RecordsGrantAuthorizationConditionPublicationProhibited, 'PermissionsGrant prohibits message from being published');
        }
    }
    /**
     * Checks if scope has no restrictions beyond interface and method.
     * Grant-holder is authorized to access any record.
     */
    static isUnrestrictedScope(grantScope) {
        return grantScope.protocol === undefined &&
            grantScope.schema === undefined;
    }
}
//# sourceMappingURL=records-grant-authorization.js.map