Skip to content

Commit

Permalink
test TOS acceptance
Browse files Browse the repository at this point in the history
  • Loading branch information
finn-block committed Nov 17, 2023
1 parent 5764b43 commit 853f8d7
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 8 deletions.
23 changes: 20 additions & 3 deletions src/tenant-gate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export class TenantGate {
return true;
}

async authorizeTenant(tenant: string): Promise<void> {
async authorizeTenantPOW(tenant: string): Promise<void> {
await this.#db
.insertInto('authorizedTenants')
.values({
Expand Down Expand Up @@ -166,7 +166,7 @@ export class TenantGate {
}

try {
await this.authorizeTenant(body.did);
await this.authorizeTenantPOW(body.did);
} catch (e) {
console.log('error inserting did', e);
res.status(500).json({ success: false });
Expand Down Expand Up @@ -202,7 +202,8 @@ export class TenantGate {

if (body.tosHash != this.#tosHash) {
res.status(400).json({
error: 'incorrect TOS hash',
success: false,
reason: 'incorrect TOS hash',
});
}

Expand All @@ -218,6 +219,22 @@ export class TenantGate {
})),
)
.executeTakeFirst();
res.status(200).json({ success: true });
}

async authorizeTenantTOS(tenant: string): Promise<void> {
await this.#db
.insertInto('authorizedTenants')
.values({
did: tenant,
tos: this.#tosHash,
})
.onConflict((oc) =>
oc.column('did').doUpdateSet((eb) => ({
tos: eb.ref('excluded.tos'),
})),
)
.executeTakeFirst();
}
}

Expand Down
88 changes: 84 additions & 4 deletions tests/http-api.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
import type { Dwn } from '@tbd54566975/dwn-sdk-js';

import { expect } from 'chai';
import { createHash } from 'crypto';
import { readFileSync } from 'fs';
import type { Server } from 'http';
import fetch from 'node-fetch';
import { webcrypto } from 'node:crypto';
Expand Down Expand Up @@ -54,15 +56,16 @@ describe('http api', function () {
clock = useFakeTimers({ shouldAdvanceTime: true });

config.registrationRequirementPow = true;
const testdwn = await getTestDwn(true);
const testdwn = await getTestDwn(true, true);
dwn = testdwn.dwn;
tenantGate = testdwn.tenantGate;

httpApi = new HttpApi(dwn, tenantGate);

await tenantGate.initialize();
profile = await createProfile();
tenantGate.authorizeTenant(profile.did);
await tenantGate.authorizeTenantPOW(profile.did);
await tenantGate.authorizeTenantTOS(profile.did);
});

beforeEach(async function () {
Expand Down Expand Up @@ -159,7 +162,7 @@ describe('http api', function () {

it('increase complexity as more challenges are completed', async function () {
for (let i = 1; i <= 60; i++) {
tenantGate.authorizeTenant((await createProfile()).did);
tenantGate.authorizeTenantPOW((await createProfile()).did);
}

const p = await createProfile();
Expand Down Expand Up @@ -272,7 +275,7 @@ describe('http api', function () {
expect(submitResponse.status).to.equal(401);
});

it('rejects unauthorized tenants', async function () {
it('rejects tenants that have not accepted the TOS and have not completed POW', async function () {
const unauthorized = await createProfile();
const recordsQuery = await RecordsQuery.create({
filter: { schema: 'woosa' },
Expand All @@ -294,6 +297,83 @@ describe('http api', function () {
expect(response.body.id).to.equal(requestId);
expect(response.body.result.reply.status.code).to.equal(401);
});

it('rejects tenants that have accepted the TOS but not completed POW', async function () {
const unauthorized = await createProfile();
await tenantGate.authorizeTenantTOS(unauthorized.did);
const recordsQuery = await RecordsQuery.create({
filter: { schema: 'woosa' },
signer: unauthorized.signer,
});

const requestId = uuidv4();
const dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', {
message: recordsQuery.toJSON(),
target: unauthorized.did,
});

const response = await request(httpApi.api)
.post('/')
.set('dwn-request', JSON.stringify(dwnRequest))
.send();

expect(response.statusCode).to.equal(200);
expect(response.body.id).to.equal(requestId);
expect(response.body.result.reply.status.code).to.equal(401);
});
});

describe('/register/tos', function () {
it('correctly accept tos', async function () {
const response = await fetch('http://localhost:3000/register/tos');
expect(response.status).to.equal(200);

const terms = await response.text();

expect(terms).to.equal(
readFileSync('./tests/fixtures/tos.txt').toString(),
);

const hash = createHash('sha256');
hash.update(terms);

const p = await createProfile();

const acceptResponse = await fetch('http://localhost:3000/register/tos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
did: p.did,
tosHash: hash.digest('hex'),
}),
});

expect(acceptResponse.status).to.equal(200);
}).timeout(30000);

it('rejects tenants that have completed POW but have not accepted the TOS', async function () {
const unauthorized = await createProfile();
await tenantGate.authorizeTenantPOW(unauthorized.did);
const recordsQuery = await RecordsQuery.create({
filter: { schema: 'woosa' },
signer: unauthorized.signer,
});

const requestId = uuidv4();
const dwnRequest = createJsonRpcRequest(requestId, 'dwn.processMessage', {
message: recordsQuery.toJSON(),
target: unauthorized.did,
});

const response = await request(httpApi.api)
.post('/')
.set('dwn-request', JSON.stringify(dwnRequest))
.send();

expect(response.statusCode).to.equal(200);
expect(response.body.id).to.equal(requestId);
expect(response.body.result.reply.status.code).to.equal(401);
});
});

describe('/ (rpc)', function () {
Expand Down
9 changes: 8 additions & 1 deletion tests/test-dwn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
MessageStoreSql,
} from '@tbd54566975/dwn-sql-store';

import { readFileSync } from 'node:fs';

import { getDialectFromURI } from '../src/storage.js';
import { TenantGate } from '../src/tenant-gate.js';

Expand All @@ -19,7 +21,12 @@ export async function getTestDwn(
const dataStore = new DataStoreSql(db);
const eventLog = new EventLogSql(db);
const messageStore = new MessageStoreSql(db);
const tenantGate = new TenantGate(db, powRequired, tosRequired);
const tenantGate = new TenantGate(
db,
powRequired,
tosRequired,
tosRequired ? readFileSync('./tests/fixtures/tos.txt').toString() : null,
);

let dwn: Dwn;
try {
Expand Down

0 comments on commit 853f8d7

Please sign in to comment.