Skip to content

Commit

Permalink
Initial setup
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Le Cam committed Jun 17, 2019
0 parents commit 0870d14
Show file tree
Hide file tree
Showing 26 changed files with 9,000 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
extends: ['mainframe', 'mainframe/jest', 'mainframe/typescript'],
rules: {
'@typescript-eslint/explicit-function-return-type': {
allowExpressions: true,
},
},
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Ægle

Data formats and protocols for decentralised applications over Swarm

Work in progress - not much to see here
210 changes: 210 additions & 0 deletions __tests__/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import Bzz from '@erebos/api-bzz-node'
import { createKeyPair, sign } from '@erebos/secp256k1'

import {
// protocols
createPeerPublisher,
createPeerSubscriber,
// channels
getPublicAddress,
getFeedReadParams,
getFeedWriteParams,
// constants
HEADER_MAX_SIZE,
HEADER_SIZE_BYTES,
// crypto
randomBytesAsync,
decrypt,
encrypt,
// encoding
encodeHeaderSize,
decodeHeaderSize,
} from '../packages/core/src'

describe('channels', () => {
test('getPublicAddress() returns the address from a KeyPair', () => {
const keyPair = createKeyPair()
const address = getPublicAddress(keyPair)
expect(address).toMatch(/^0x[0-9a-f]{40}$/)
})

describe('getFeedReadParams() returns the parameter to read a given feed', () => {
test('for a simple case (publisher public key only)', () => {
const publisher = createKeyPair()
const params = getFeedReadParams(publisher.getPublic('hex'))
expect(params).toEqual({
feed: { user: getPublicAddress(publisher) },
encryptionKey: undefined,
})
})

test('with a feed name', () => {
const publisher = createKeyPair()
const params = getFeedReadParams(publisher.getPublic('hex'), 'hello')
expect(params).toEqual({
feed: { user: getPublicAddress(publisher), name: 'hello' },
encryptionKey: undefined,
})
})

test('with a subscriber key pair', () => {
const publisher = createKeyPair(
'1d64177e47720f8a23b96815400a4375fb069f9245bbb219107e250c531d0815',
)
const subscriber = createKeyPair(
'b80c8c86f96a6137629b34126434d852bdbeb0f7f2ca0b81f4321163e97c2eb0',
)
const params = getFeedReadParams(
publisher.getPublic('hex'),
'hello',
subscriber,
)
expect(params).toEqual({
feed: {
user: getPublicAddress(publisher),
topic:
'0x637d335c780a0685255fc84f6495d05de5732a06000000000000000000000000',
},
encryptionKey: Buffer.from(
'GULmdGUtw7mLiJa3sxRmcYZfX3iASunp/3sDadsBMrA=',
'base64',
),
})
})
})

describe('getFeedWriteParams() returns the parameter to write a given feed', () => {
test('for a simple case (publisher key pair only)', () => {
const keyPair = createKeyPair()
const params = getFeedWriteParams(keyPair)
expect(params).toEqual({
feed: { user: getPublicAddress(keyPair) },
encryptionKey: undefined,
signParams: keyPair.getPrivate(),
})
})

test('with a feed name', () => {
const keyPair = createKeyPair()
const params = getFeedWriteParams(keyPair, 'hello')
expect(params).toEqual({
feed: { user: getPublicAddress(keyPair), name: 'hello' },
encryptionKey: undefined,
signParams: keyPair.getPrivate(),
})
})

test('with a subscriber public key', () => {
const publisher = createKeyPair(
'1d64177e47720f8a23b96815400a4375fb069f9245bbb219107e250c531d0815',
)
const subscriber = createKeyPair(
'b80c8c86f96a6137629b34126434d852bdbeb0f7f2ca0b81f4321163e97c2eb0',
)
const params = getFeedWriteParams(
publisher,
'hello',
subscriber.getPublic('hex'),
)
expect(params).toEqual({
feed: {
user: getPublicAddress(publisher),
topic:
'0x637d335c780a0685255fc84f6495d05de5732a06000000000000000000000000',
},
encryptionKey: Buffer.from(
'GULmdGUtw7mLiJa3sxRmcYZfX3iASunp/3sDadsBMrA=',
'base64',
),
signParams: publisher.getPrivate(),
})
})
})

test.todo('createEntityPublisher()')
test.todo('createFeedPublisher()')
test.todo('createTimelinePublisher()')
test.todo('createFeedSubscriber()')
test.todo('createTimelineDecoder()')
test.todo('createReadTimeline()')
test.todo('createTimelineLatestSubscriber()')
test.todo('createTimelineLiveSubscriber()')
})

describe('crypto', () => {
test('randomBytesAsync()', async () => {
const [someBytes, otherBytes] = await Promise.all([
randomBytesAsync(16),
randomBytesAsync(16),
])
expect(someBytes.length).toBe(16)
expect(otherBytes.length).toBe(16)
expect(someBytes.equals(otherBytes)).toBe(false)
})

test('encrypts and decrypts', async () => {
const key = await randomBytesAsync(32)
const data = { hello: 'test' }
const payload = await encrypt('aes-256-gcm', key, data)
const decrypted = await decrypt(key, payload)
expect(decrypted).toEqual(data)

const otherKey = await randomBytesAsync(32)
await expect(decrypt(otherKey, payload)).rejects.toThrow(
'Unsupported state or unable to authenticate data',
)
})
})

describe('encoding', () => {
test('encodes header size', () => {
const encoded = encodeHeaderSize(1000)
expect(encoded).toHaveLength(HEADER_SIZE_BYTES)

expect(() => {
encodeHeaderSize(-1)
}).toThrow('Out of bounds header size')
expect(() => {
encodeHeaderSize(HEADER_MAX_SIZE + 1)
}).toThrow('Out of bounds header size')
})

test('decodes header size', () => {
const encoded = encodeHeaderSize(1000)
expect(decodeHeaderSize(encoded)).toBe(1000)

expect(() => {
decodeHeaderSize(Buffer.alloc(HEADER_SIZE_BYTES + 1))
}).toThrow('Invalid input')
})
})

describe('protocols', () => {
test('peer', async done => {
const bzz = new Bzz({
url: 'http://localhost:8500',
signBytes: async (bytes, key) => sign(bytes, key),
})
const keyPair = createKeyPair()
const pubKey = keyPair.getPublic('hex')
const peer = {
publicKey: pubKey,
profile: {
displayName: 'Alice',
},
}

const subscription = createPeerSubscriber(bzz, pubKey, {
interval: 1000,
}).subscribe({
next: loadedPeer => {
expect(loadedPeer).toEqual(peer)
subscription.unsubscribe()
done()
},
})

const publish = createPeerPublisher(bzz, keyPair)
await publish(peer)
})
})
11 changes: 11 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
globals: {
'ts-jest': {
diagnostics: false,
},
},
testEnvironment: 'node',
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
}
48 changes: 48 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "aegle",
"version": "1.0.0",
"description": "Data formats and protocols over Swarm",
"repository": "[email protected]:MainframeHQ/aegle.git",
"main": "index.js",
"author": "Mainframe",
"license": "MIT",
"private": true,
"workspaces": {
"packages": [
"packages/*"
],
"nohoist": []
},
"scripts": {
"clean": "lerna clean -y && del-cli ./node_modules",
"lint": "eslint 'packages/*/src/**.ts' '__tests__/**.ts'",
"lint:fix": "yarn lint --fix",
"test:types": "lerna run test:types",
"test:unit": "BABEL_ENV=test jest --config jest.config.js",
"test:ci": "BABEL_ENV=test jest --ci --config jest.config.ci.js --runInBand",
"test": "yarn lint && yarn test:types && yarn test:unit",
"build": "lerna run build",
"start": "yarn build && yarn test"
},
"devDependencies": {
"@babel/cli": "^7.0.0",
"@babel/core": "^7.1.6",
"@babel/plugin-proposal-class-properties": "^7.3.3",
"@babel/plugin-transform-runtime": "^7.0.0",
"@babel/preset-env": "^7.1.6",
"@babel/preset-typescript": "^7.3.3",
"@types/jest": "^24.0.15",
"babel-eslint": "^10.0.1",
"babel-jest": "^24.1.0",
"del-cli": "^2.0.0",
"eslint": "^5.9.0",
"eslint-config-mainframe": "^3.0.0",
"jest": "^24.1.0",
"jest-junit": "^6.2.1",
"lerna": "^3.15.0",
"prettier": "^1.18.2",
"ts-jest": "^24.0.2",
"typescript": "^3.5.2",
"typescript-eslint-parser": "^22.0.0"
}
}
36 changes: 36 additions & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@aegle/core",
"version": "0.1.0",
"description": "Aegle core",
"repository": "[email protected]:MainframeHQ/aegle.git",
"main": "lib/index.js",
"types": "types/index.d.ts",
"author": "Mainframe",
"license": "MIT",
"files": [
"lib/*",
"types/*"
],
"scripts": {
"clean": "del lib types",
"build:js": "BABEL_ENV=node babel src --out-dir lib --extensions \".ts\"",
"build:types": "tsc --emitDeclarationOnly",
"build": "yarn clean && yarn build:js && yarn build:types",
"test:types": "tsc --noEmit",
"prepublishOnly": "yarn build"
},
"dependencies": {
"@erebos/api-bzz-base": "^0.8.1",
"@erebos/keccak256": "^0.7.0",
"@erebos/secp256k1": "^0.7.0",
"@erebos/timeline": "^0.8.0",
"@types/elliptic": "^6.4.9",
"ajv": "^6.10.0",
"get-stream": "^5.1.0",
"p-queue": "^6.0.2",
"rxjs": "^6.5.2"
},
"devDependencies": {
"@erebos/api-bzz-node": "^0.8.1"
}
}
Loading

0 comments on commit 0870d14

Please sign in to comment.