-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from HDegroote/add-test
Add --private flag + add some end-to-end tests
- Loading branch information
Showing
6 changed files
with
262 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
name: Build Status | ||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
branches: | ||
- main | ||
jobs: | ||
build: | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, macos-latest, windows-latest] | ||
runs-on: ${{ matrix.os }} | ||
steps: | ||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 https://github.com/actions/checkout/releases/tag/v4.1.1 | ||
- name: Use Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3.8.2 https://github.com/actions/setup-node/releases/tag/v3.8.2 | ||
with: | ||
node-version: 18 | ||
- run: npm install | ||
- run: npm test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
const { spawn } = require('child_process') | ||
const { once } = require('events') | ||
const path = require('path') | ||
const http = require('http') | ||
const createTestnet = require('hyperdht/testnet') | ||
const test = require('brittle') | ||
const HyperDHT = require('hyperdht') | ||
const b4a = require('b4a') | ||
|
||
const MAIN_DIR = path.dirname(__dirname) | ||
const SERVER_EXECUTABLE = path.join(MAIN_DIR, 'server.js') | ||
const CLIENT_EXECUTABLE = path.join(MAIN_DIR, 'client.js') | ||
|
||
test('Can proxy in private mode', async t => { | ||
const { bootstrap } = await createTestnet(3, t.teardown) | ||
const portToProxy = await setupDummyServer(t.teardown) | ||
const seed = 'a'.repeat(64) | ||
|
||
await setupHyperteleServer(portToProxy, seed, bootstrap, t, { isPrivate: true }) | ||
const clientPort = await setupHyperteleClient(seed, bootstrap, t, { isPrivate: true }) | ||
|
||
const res = await request(clientPort) | ||
t.is(res.data, 'You got served', 'Proxy works') | ||
}) | ||
|
||
test('Cannot access private-mode server with public key', async t => { | ||
const { bootstrap } = await createTestnet(3, t.teardown) | ||
const portToProxy = await setupDummyServer(t.teardown) | ||
const seed = 'a'.repeat(64) | ||
const keypair = HyperDHT.keyPair(b4a.from(seed, 'hex')) | ||
const pubKey = b4a.toString(keypair.publicKey, 'hex') | ||
|
||
await setupHyperteleServer(portToProxy, seed, bootstrap, t, { isPrivate: true }) | ||
const clientPort = await setupHyperteleClient(pubKey, bootstrap, t, { isPrivate: false }) | ||
|
||
// Could also be a socket hangup if more time is given | ||
await t.exception(async () => await request(clientPort), /Request timeout/) | ||
}) | ||
|
||
test('Can proxy in non-private mode', async t => { | ||
const { bootstrap } = await createTestnet(3, t.teardown) | ||
const portToProxy = await setupDummyServer(t.teardown) | ||
const seed = 'a'.repeat(64) | ||
const keypair = HyperDHT.keyPair(b4a.from(seed, 'hex')) | ||
const pubKey = b4a.toString(keypair.publicKey, 'hex') | ||
|
||
await setupHyperteleServer(portToProxy, seed, bootstrap, t, { isPrivate: false }) | ||
const clientPort = await setupHyperteleClient(pubKey, bootstrap, t, { isPrivate: false }) | ||
|
||
const res = await request(clientPort) | ||
t.is(res.data, 'You got served', 'Proxy works') | ||
}) | ||
|
||
async function setupDummyServer (teardown) { | ||
const server = http.createServer(async (req, res) => { | ||
res.setHeader('Content-Type', 'text/html; charset=utf-8') | ||
res.end('You got served') | ||
}) | ||
teardown(() => server.close()) | ||
|
||
server.listen({ port: 0, host: '127.0.0.1' }) | ||
await once(server, 'listening') | ||
return server.address().port | ||
} | ||
|
||
async function setupHyperteleServer (portToProxy, seed, bootstrap, t, { isPrivate = false } = {}) { | ||
const args = [ | ||
SERVER_EXECUTABLE, | ||
'-l', | ||
portToProxy, | ||
'--seed', | ||
seed, | ||
'--bootstrap', | ||
bootstrap[0].port | ||
] | ||
if (isPrivate) args.push('--private') | ||
|
||
const setupServer = spawn('node', args) | ||
t.teardown(() => setupServer.kill('SIGKILL')) | ||
|
||
setupServer.stderr.on('data', (data) => { | ||
console.error(data.toString()) | ||
t.fail('Failed to setup hypertele server') | ||
}) | ||
|
||
await new Promise(resolve => { | ||
setupServer.stdout.on('data', (data) => { | ||
if (data.includes('hypertele')) { | ||
resolve() | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
async function setupHyperteleClient (seed, bootstrap, t, { isPrivate = false } = {}) { | ||
const args = [ | ||
CLIENT_EXECUTABLE, | ||
'-p', | ||
0, // random | ||
'-s', | ||
seed, | ||
'--bootstrap', | ||
bootstrap[0].port | ||
] | ||
if (isPrivate) args.push('--private') | ||
|
||
const setupClient = spawn('node', args) | ||
t.teardown(() => setupClient.kill('SIGKILL')) | ||
|
||
setupClient.stderr.on('data', (data) => { | ||
console.error(data.toString()) | ||
t.fail('Failed to setup hypertele client') | ||
}) | ||
|
||
const clientPort = await new Promise(resolve => { | ||
setupClient.stdout.on('data', (data) => { | ||
const msg = data.toString() | ||
if (msg.includes('Server ready')) { | ||
const port = msg.slice(msg.search(':') + 1) | ||
resolve(port) | ||
} | ||
}) | ||
}) | ||
|
||
return clientPort | ||
} | ||
|
||
async function request (port, { msTimeout = 500 } = {}) { | ||
const link = `http://127.0.0.1:${port}` | ||
|
||
return new Promise((resolve, reject) => { | ||
const req = http.get(link, { | ||
headers: { | ||
Connection: 'close' | ||
} | ||
}) | ||
|
||
req.setTimeout(msTimeout, | ||
() => { | ||
reject(new Error('Request timeout')) | ||
req.destroy() | ||
} | ||
) | ||
|
||
req.on('error', reject) | ||
req.on('response', function (res) { | ||
let buf = '' | ||
|
||
res.setEncoding('utf-8') | ||
|
||
res.on('data', function (data) { | ||
buf += data | ||
}) | ||
|
||
res.on('end', function () { | ||
resolve({ status: res.statusCode, data: buf }) | ||
}) | ||
}) | ||
}) | ||
} |