| 'use strict'; |
| const common = require('../common'); |
| if (!common.hasCrypto) |
| common.skip('missing crypto'); |
| |
| const assert = require('assert'); |
| const { createSecretKey, generateKeyPairSync, randomBytes } = require('crypto'); |
| const { createContext } = require('vm'); |
| const { |
| MessageChannel, |
| Worker, |
| moveMessagePortToContext, |
| parentPort |
| } = require('worker_threads'); |
| |
| function keyToString(key) { |
| let ret; |
| if (key.type === 'secret') { |
| ret = key.export().toString('hex'); |
| } else { |
| ret = key.export({ type: 'pkcs1', format: 'pem' }); |
| } |
| return ret; |
| } |
| |
| // Worker threads simply reply with their representation of the received key. |
| if (process.env.HAS_STARTED_WORKER) { |
| return parentPort.once('message', ({ key }) => { |
| parentPort.postMessage(keyToString(key)); |
| }); |
| } |
| |
| // Don't use isMainThread to allow running this test inside a worker. |
| process.env.HAS_STARTED_WORKER = 1; |
| |
| // The main thread generates keys and passes them to worker threads. |
| const secretKey = createSecretKey(randomBytes(32)); |
| const { publicKey, privateKey } = generateKeyPairSync('rsa', { |
| modulusLength: 1024 |
| }); |
| |
| // Get immutable representations of all keys. |
| const keys = [secretKey, publicKey, privateKey] |
| .map((key) => [key, keyToString(key)]); |
| |
| for (const [key, repr] of keys) { |
| { |
| // Test 1: No context change. |
| const { port1, port2 } = new MessageChannel(); |
| |
| port1.postMessage({ key }); |
| assert.strictEqual(keyToString(key), repr); |
| |
| port2.once('message', common.mustCall(({ key }) => { |
| assert.strictEqual(keyToString(key), repr); |
| })); |
| } |
| |
| { |
| // Test 2: Across threads. |
| const worker = new Worker(__filename); |
| worker.once('message', common.mustCall((receivedRepresentation) => { |
| assert.strictEqual(receivedRepresentation, repr); |
| })); |
| worker.on('disconnect', () => console.log('disconnect')); |
| worker.postMessage({ key }); |
| } |
| |
| { |
| // Test 3: Across contexts (should not work). |
| const { port1, port2 } = new MessageChannel(); |
| const context = createContext(); |
| const port2moved = moveMessagePortToContext(port2, context); |
| assert(!(port2moved instanceof Object)); |
| |
| // TODO(addaleax): Switch this to a 'messageerror' event once MessagePort |
| // implements EventTarget fully and in a cross-context manner. |
| port2moved.onmessageerror = common.mustCall((event) => { |
| assert.strictEqual(event.data.code, |
| 'ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE'); |
| }); |
| |
| port2moved.start(); |
| port1.postMessage({ key }); |
| port1.close(); |
| } |
| } |