Skip to content

Commit

Permalink
feat: 🎸 add integrity check on read
Browse files Browse the repository at this point in the history
  • Loading branch information
streamich committed Jun 21, 2023
1 parent 5c851a7 commit 710eb2f
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
2 changes: 1 addition & 1 deletion docs/casfs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const blob2 = await cas.get(hash);
You can also delete blobs:

```js
await cas.delete(hash);
await cas.del(hash);
```

And retrieve information about blobs:
Expand Down
11 changes: 8 additions & 3 deletions src/crud-to-cas/CrudCas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { hashToLocation } from './util';
import type { CasApi } from '../cas/types';
import type { CasApi, CasGetOptions } from '../cas/types';
import type { CrudApi, CrudResourceInfo } from '../crud/types';

export interface CrudCasOptions {
Expand Down Expand Up @@ -31,10 +31,15 @@ export class CrudCas implements CasApi {
return digest;
};

public readonly get = async (hash: string): Promise<Uint8Array> => {
public readonly get = async (hash: string, options?: CasGetOptions): Promise<Uint8Array> => {
const [collection, resource] = hashToLocation(hash);
return await normalizeErrors(async () => {
return await this.crud.get(collection, resource);
const blob = await this.crud.get(collection, resource);
if (!options?.skipVerification) {
const digest = await this.options.hash(blob);
if (hash !== digest) throw new DOMException('Blob contents does not match hash', 'Integrity');
}
return blob;
});
};

Expand Down
22 changes: 22 additions & 0 deletions src/crud-to-cas/__tests__/CrudCas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { onlyOnNode20 } from '../../__tests__/util';
import { NodeFileSystemDirectoryHandle } from '../../node-to-fsa';
import { FsaCrud } from '../../fsa-to-crud/FsaCrud';
import { CrudCas } from '../CrudCas';
import { hashToLocation } from '../util';

const hash = async (blob: Uint8Array): Promise<string> => {
const shasum = createHash('sha1');
Expand Down Expand Up @@ -53,6 +54,27 @@ onlyOnNode20('CrudCas', () => {
expect(err).toBeInstanceOf(DOMException);
expect((<any>err).name).toBe('BlobNotFound');
});

test('throws if blob contents does not match the hash', async () => {
const blob = b('hello world');
const { cas, crud } = setup();
const hash = await cas.put(blob);
const location = hashToLocation(hash);
await crud.put(location[0], location[1], b('hello world!'));
const [, err] = await of(cas.get(hash));
expect(err).toBeInstanceOf(DOMException);
expect((<any>err).name).toBe('Integrity');
});

test('does not throw if integrity check is skipped', async () => {
const blob = b('hello world');
const { cas, crud } = setup();
const hash = await cas.put(blob);
const location = hashToLocation(hash);
await crud.put(location[0], location[1], b('hello world!'));
const blob2 = await cas.get(hash, { skipVerification: true });
expect(blob2).toStrictEqual(b('hello world!'));
});
});

describe('.info()', () => {
Expand Down

0 comments on commit 710eb2f

Please sign in to comment.