Skip to content

Instantly share code, notes, and snippets.

@jwerle
Last active March 15, 2019 00:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwerle/2db20a1bdf2c497a9d64ed36337393b7 to your computer and use it in GitHub Desktop.
Save jwerle/2db20a1bdf2c497a9d64ed36337393b7 to your computer and use it in GitHub Desktop.
compile javascript and encrypt into native module - blah
node_modules/
package-lock.json
plugin.c
plugin.node
#!/usr/bin/env node
const {
readFileSync: readFile,
writeFileSync: writeFile,
} = require('fs')
const crypto = require('ara-crypto')
function map(line) {
return `"${line}\\n"`
}
function split(buf) {
var list = []
for (var i = 0; i < buf.length; i += 65535) {
list.push(buf.slice(i, i + 65535))
}
return list
}
const secret = crypto.blake2b(Buffer.from(process.argv[2]), 64)
const source = String(readFile('plugin.c.in'))
const code = String(readFile('plugin/index.js'))
.replace(RegExp("\\\\'", 'g'), '\\"')
.replace(RegExp('\\\\"', 'g'), '\\\\"')
.replace(RegExp('\\\\\\\\', 'g'), '\\\\\\\\')
.replace(/"/g, '\\"')
.split('\n')
.map(map)
.join('\n')
const lines = split(Buffer.from(code))
const boxes = lines.map((line) => crypto.box(Buffer.from(line), { secret }))
const plugin = boxes.map((box) => box.toString('hex')).join('|')
const wrapper = `(function(payload) {
__dirname = 'not available'
let sourceString = null
try {
const secret = Buffer.from('${secret.toString('hex')}', 'hex')
const crypto = require('ara-crypto')
const boxes = payload.split('|').map((hex) => Buffer.from(hex, 'hex'))
const unboxes = boxes.map((box) => crypto.unbox(box, { secret }))
const source = unboxes.reduce((buf, out) => Buffer.concat([buf, out]), Buffer.alloc(0))
const lines = String(source).split('\\\\n')
sourceString = lines.join('+ \\\\n')
} catch (err) {
console.error(err.stack || err)
return
}
if (null !== sourceString) {
eval('string =' + sourceString)
eval(string)
}
})('${plugin}')
`.split('\n').map(map).join('\n')
const output = Buffer.from(source.replace('{{SOURCE}}', `${wrapper}`))
writeFile('plugin.c', output)
const { init } = require('./init')
require('ara-crypto')
init()
module.exports = {
init
}
const http = require('http')
function init() {
const server = http.createServer(onrequest)
server.listen(3000)
console.log('hello world')
}
function onrequest(req, res) {
res.end('hello world')
}
module.exports = {
init
}
CC ?= gcc
SECRET ?= secrets
PREFIX ?= /usr/local
CFLAGS += -I $(shell find $(PREFIX) -name node_api.h | head -n 1 | xargs dirname)
CFLAGS += -I node_modules/napi-macros
CFLAGS += -shared -fPIC
plugin.node: plugin.c
$(CC) $(CFLAGS) -o $@ $^
plugin.c: plugin.c.in build.js
./build.js $(SECRET)
plugin.c.in: plugin/index.js build.js
plugin/index.js: index.js init.js
ncc build index.js -o plugin
{
"name": "napi-embed-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"ara-crypto": "github:arablocks/ara-crypto",
"napi-macros": "^1.8.2"
}
}
#include <node_api.h>
#include <napi-macros.h>
#include <string.h>
#include <stdio.h>
#include <sodium.h>
const char *javascript = {{SOURCE}};
NAPI_METHOD(my_plugin_init) {
const napi_extended_error_info *err = 0;
napi_value result;
napi_value string;
napi_create_string_utf8(env, javascript, strlen(javascript), &string);
napi_status rc = napi_run_script(env, string, &result);
if (0 != rc) {
napi_get_last_error_info(env, &err);
printf("error: %s\n", err->error_message);
}
printf("my_plugin_init() = %d\n", rc);
return NULL;
}
NAPI_MODULE_INIT() {
printf("Init plugin\n");
NAPI_EXPORT_FUNCTION(my_plugin_init)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment