diff --git a/src/tenant-gate.ts b/src/tenant-gate.ts index 7e5eaa2..4aacb6b 100644 --- a/src/tenant-gate.ts +++ b/src/tenant-gate.ts @@ -15,12 +15,14 @@ export class TenantGate { #tosRequired: boolean; #tos?: string; #tosHash?: string; + #logRejections: boolean; constructor( dialect: Dialect, powRequired: boolean, tosRequired: boolean, currentTOS?: string, + logRejections?: boolean, ) { this.#db = new Kysely({ dialect: dialect }); this.#powRequired = powRequired; @@ -31,6 +33,7 @@ export class TenantGate { tosHash.update(currentTOS); this.#tosHash = tosHash.digest('hex'); } + this.#logRejections = logRejections || false; } async initialize(): Promise { @@ -86,16 +89,24 @@ export class TenantGate { .execute(); if (result.length == 0) { + console.log('rejecting tenant that is not in the database', { tenant }); return false; } const row = result[0]; if (this.#powRequired && row.powTime == undefined) { + console.log('rejecting tenant that has not completed the proof of work', { + tenant, + }); return false; } if (this.#tosRequired && row.tos != this.#tosHash) { + console.log( + 'rejecting tenant that has not accepted the current terms of service', + { row, tenant, expected: this.#tosHash }, + ); return false; } @@ -207,6 +218,8 @@ export class TenantGate { }); } + console.log('accepting tos', body); + await this.#db .insertInto('authorizedTenants') .values({ @@ -218,7 +231,7 @@ export class TenantGate { tos: eb.ref('excluded.tos'), })), ) - .executeTakeFirst(); + .executeTakeFirstOrThrow(); res.status(200).json({ success: true }); } diff --git a/tests/http-api.spec.ts b/tests/http-api.spec.ts index baa4607..ecb4302 100644 --- a/tests/http-api.spec.ts +++ b/tests/http-api.spec.ts @@ -123,6 +123,29 @@ describe('http api', function () { }); expect(submitResponse.status).to.equal(200); + + await tenantGate.authorizeTenantTOS(p.did); + + const recordsQuery = await RecordsQuery.create({ + filter: { schema: 'woosa' }, + signer: p.signer, + }); + + const requestId = uuidv4(); + const dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', { + message: recordsQuery.toJSON(), + target: p.did, + }); + + const rpcResponse = await request(httpApi.api) + .post('/') + .set('dwn-request', JSON.stringify(dwnRequest)) + .send(); + + console.log(rpcResponse.body.result.reply.status); + expect(rpcResponse.statusCode).to.equal(200); + expect(rpcResponse.body.id).to.equal(requestId); + expect(rpcResponse.body.result.reply.status.code).to.equal(200); }).timeout(30000); it('rejects a registration challenge 5 minutes after it was issued', async function () { @@ -324,7 +347,7 @@ describe('http api', function () { }); describe('/register/tos', function () { - it('correctly accept tos', async function () { + it('allow tenant that after accepting the terms of service', async function () { const response = await fetch('http://localhost:3000/register/tos'); expect(response.status).to.equal(200); @@ -347,9 +370,30 @@ describe('http api', function () { tosHash: hash.digest('hex'), }), }); - expect(acceptResponse.status).to.equal(200); - }).timeout(30000); + await tenantGate.authorizeTenantPOW(p.did); + + const recordsQuery = await RecordsQuery.create({ + filter: { schema: 'woosa' }, + signer: p.signer, + }); + + const requestId = uuidv4(); + const dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', { + message: recordsQuery.toJSON(), + target: p.did, + }); + + const rpcResponse = await request(httpApi.api) + .post('/') + .set('dwn-request', JSON.stringify(dwnRequest)) + .send(); + + console.log(rpcResponse.body.result.reply.status); + expect(rpcResponse.statusCode).to.equal(200); + expect(rpcResponse.body.id).to.equal(requestId); + expect(rpcResponse.body.result.reply.status.code).to.equal(200); + }); it('rejects tenants that have completed POW but have not accepted the TOS', async function () { const unauthorized = await createProfile(); @@ -525,14 +569,18 @@ describe('http api', function () { }); it('handles RecordsWrite overwrite that does not mutate data', async function () { + const p = await createProfile(); + await tenantGate.authorizeTenantPOW(p.did); + await tenantGate.authorizeTenantTOS(p.did); + // First RecordsWrite that creates the record. const { recordsWrite: initialWrite, dataStream } = - await createRecordsWriteMessage(profile); + await createRecordsWriteMessage(p); const dataBytes = await DataStream.toBytes(dataStream); let requestId = uuidv4(); let dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', { message: initialWrite.toJSON(), - target: profile.did, + target: p.did, }); const responseInitialWrite = await fetch('http://localhost:3000', { @@ -546,21 +594,18 @@ describe('http api', function () { expect(responseInitialWrite.status).to.equal(200); // Subsequent RecordsWrite that mutates the published property of the record. - const { recordsWrite: overWrite } = await createRecordsWriteMessage( - profile, - { - recordId: initialWrite.message.recordId, - dataCid: initialWrite.message.descriptor.dataCid, - dataSize: initialWrite.message.descriptor.dataSize, - dateCreated: initialWrite.message.descriptor.dateCreated, - published: true, - }, - ); + const { recordsWrite: overWrite } = await createRecordsWriteMessage(p, { + recordId: initialWrite.message.recordId, + dataCid: initialWrite.message.descriptor.dataCid, + dataSize: initialWrite.message.descriptor.dataSize, + dateCreated: initialWrite.message.descriptor.dateCreated, + published: true, + }); requestId = uuidv4(); dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', { message: overWrite.toJSON(), - target: profile.did, + target: p.did, }); const responseOverwrite = await fetch('http://localhost:3000', { method: 'POST', diff --git a/tests/test-dwn.ts b/tests/test-dwn.ts index 452cc2d..f02979e 100644 --- a/tests/test-dwn.ts +++ b/tests/test-dwn.ts @@ -26,6 +26,7 @@ export async function getTestDwn( powRequired, tosRequired, tosRequired ? readFileSync('./tests/fixtures/tos.txt').toString() : null, + true, ); let dwn: Dwn;