Move some things to C that probably should have never been in JS, especially sha1. Minor refactors, cleanup, and deletes along the way.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4154 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
48cd08e095
commit
7091b6e6a5
@ -1,5 +1,4 @@
|
|||||||
import * as core from './core.js';
|
import * as core from './core.js';
|
||||||
import * as http from './http.js';
|
|
||||||
import * as form from './form.js';
|
import * as form from './form.js';
|
||||||
|
|
||||||
var gTokens = {};
|
var gTokens = {};
|
||||||
|
59
core/http.js
59
core/http.js
@ -1,59 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
function parseUrl(url) {
|
|
||||||
// XXX: Hack.
|
|
||||||
var match = url.match(new RegExp("(\\w+)://([^/]+)?(.*)"));
|
|
||||||
return {
|
|
||||||
protocol: match[1],
|
|
||||||
host: match[2],
|
|
||||||
path: match[3],
|
|
||||||
port: match[1] == "http" ? 80 : 443,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseResponse(data) {
|
|
||||||
var firstLine;
|
|
||||||
var headers = {};
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
var endLine = data.indexOf("\r\n");
|
|
||||||
var line = data.substring(0, endLine);
|
|
||||||
if (!firstLine) {
|
|
||||||
firstLine = line;
|
|
||||||
} else if (!line.length) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
var colon = line.indexOf(":");
|
|
||||||
headers[line.substring(colon)] = line.substring(colon + 1);
|
|
||||||
}
|
|
||||||
data = data.substring(endLine + 2);
|
|
||||||
}
|
|
||||||
return {body: data};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function get(url) {
|
|
||||||
var parsed = parseUrl(url);
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
var socket = new Socket();
|
|
||||||
var buffer = "";
|
|
||||||
|
|
||||||
return socket.connect(parsed.host, parsed.port).then(function() {
|
|
||||||
socket.read(function(data) {
|
|
||||||
if (data) {
|
|
||||||
buffer += data;
|
|
||||||
} else {
|
|
||||||
resolve(parseResponse(buffer));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (parsed.port == 443) {
|
|
||||||
return socket.startTls();
|
|
||||||
}
|
|
||||||
}).then(function() {
|
|
||||||
socket.write(`GET ${parsed.path} HTTP/1.0\r\nHost: ${parsed.host}\r\nConnection: close\r\n\r\n`);
|
|
||||||
socket.shutdown();
|
|
||||||
}).catch(function(error) {
|
|
||||||
reject(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
@ -1,4 +1,3 @@
|
|||||||
import * as sha1 from './sha1.js';
|
|
||||||
import * as core from './core.js';
|
import * as core from './core.js';
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
@ -196,7 +195,7 @@ function handleRequest(request, response) {
|
|||||||
|
|
||||||
function handleWebSocketRequest(request, response, client) {
|
function handleWebSocketRequest(request, response, client) {
|
||||||
let buffer = new Uint8Array(0);
|
let buffer = new Uint8Array(0);
|
||||||
let frame = new Uint8Array(0);
|
let frame;
|
||||||
let frameOpCode = 0x0;
|
let frameOpCode = 0x0;
|
||||||
|
|
||||||
let handler = findSocketHandler(request);
|
let handler = findSocketHandler(request);
|
||||||
@ -285,19 +284,24 @@ function handleWebSocketRequest(request, response, client) {
|
|||||||
}
|
}
|
||||||
let havePayload = buffer.length >= payloadLength + 2 + 4;
|
let havePayload = buffer.length >= payloadLength + 2 + 4;
|
||||||
if (havePayload) {
|
if (havePayload) {
|
||||||
let mask = buffer.slice(maskStart, maskStart + 4);
|
let mask =
|
||||||
|
buffer[maskStart + 0] |
|
||||||
|
buffer[maskStart + 1] << 8 |
|
||||||
|
buffer[maskStart + 2] << 16 |
|
||||||
|
buffer[maskStart + 3] << 24;
|
||||||
let dataStart = maskStart + 4;
|
let dataStart = maskStart + 4;
|
||||||
let decoded = new Array(payloadLength);
|
|
||||||
let payload = buffer.slice(dataStart, dataStart + payloadLength);
|
let payload = buffer.slice(dataStart, dataStart + payloadLength);
|
||||||
|
let decoded = maskBytes(payload, mask);
|
||||||
buffer = buffer.slice(dataStart + payloadLength);
|
buffer = buffer.slice(dataStart + payloadLength);
|
||||||
for (let i = 0; i < payloadLength; i++) {
|
|
||||||
decoded[i] = payload[i] ^ mask[i % 4];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (frame) {
|
||||||
let newBuffer = new Uint8Array(frame.length + decoded.length);
|
let newBuffer = new Uint8Array(frame.length + decoded.length);
|
||||||
newBuffer.set(frame, 0);
|
newBuffer.set(frame, 0);
|
||||||
newBuffer.set(decoded, frame.length);
|
newBuffer.set(decoded, frame.length);
|
||||||
frame = newBuffer;
|
frame = newBuffer;
|
||||||
|
} else {
|
||||||
|
frame = decoded;
|
||||||
|
}
|
||||||
|
|
||||||
if (opCode) {
|
if (opCode) {
|
||||||
frameOpCode = opCode;
|
frameOpCode = opCode;
|
||||||
@ -310,7 +314,7 @@ function handleWebSocketRequest(request, response, client) {
|
|||||||
opCode: frameOpCode,
|
opCode: frameOpCode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
frame = new Uint8Array(0);
|
frame = undefined;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -340,23 +344,7 @@ function handleWebSocketRequest(request, response, client) {
|
|||||||
function webSocketAcceptResponse(key) {
|
function webSocketAcceptResponse(key) {
|
||||||
let kMagic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
let kMagic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||||
let kAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
let kAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||||
let hex = sha1.hash(key + kMagic)
|
return base64Encode(sha1Digest(key + kMagic));
|
||||||
let binary = "";
|
|
||||||
for (let i = 0; i < hex.length; i += 6) {
|
|
||||||
let characters = hex.substring(i, i + 6);
|
|
||||||
if (characters.length < 6) {
|
|
||||||
characters += "0".repeat(6 - characters.length);
|
|
||||||
}
|
|
||||||
let value = parseInt(characters, 16);
|
|
||||||
for (let bit = 0; bit < 8 * 3; bit += 6) {
|
|
||||||
if (i * 8 / 2 + bit >= 8 * hex.length / 2) {
|
|
||||||
binary += kAlphabet.charAt(64);
|
|
||||||
} else {
|
|
||||||
binary += kAlphabet.charAt((value >> (18 - bit)) & 63);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return binary;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function badRequest(client, reason) {
|
function badRequest(client, reason) {
|
||||||
|
160
core/sha1.js
160
core/sha1.js
@ -1,160 +0,0 @@
|
|||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
/* SHA-1 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */
|
|
||||||
/* */
|
|
||||||
/* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */
|
|
||||||
/* http://csrc.nist.gov/groups/ST/toolkit/examples.html */
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
/* jshint node:true *//* global define, escape, unescape */
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SHA-1 hash function reference implementation.
|
|
||||||
*
|
|
||||||
* @namespace
|
|
||||||
*/
|
|
||||||
var Sha1 = {};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates SHA-1 hash of string.
|
|
||||||
*
|
|
||||||
* @param {string} msg - (Unicode) string to be hashed.
|
|
||||||
* @returns {string} Hash of msg as hex character string.
|
|
||||||
*/
|
|
||||||
Sha1.hash = function(msg) {
|
|
||||||
// convert string to UTF-8, as SHA only deals with byte-streams
|
|
||||||
msg = msg.utf8Encode();
|
|
||||||
|
|
||||||
// constants [§4.2.1]
|
|
||||||
var K = [ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 ];
|
|
||||||
|
|
||||||
// PREPROCESSING
|
|
||||||
|
|
||||||
msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]
|
|
||||||
|
|
||||||
// convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
|
|
||||||
var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length
|
|
||||||
var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints
|
|
||||||
var M = new Array(N);
|
|
||||||
|
|
||||||
for (var i=0; i<N; i++) {
|
|
||||||
M[i] = new Array(16);
|
|
||||||
for (var j=0; j<16; j++) { // encode 4 chars per integer, big-endian encoding
|
|
||||||
M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) |
|
|
||||||
(msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
|
|
||||||
} // note running off the end of msg is ok 'cos bitwise ops on NaN return 0
|
|
||||||
}
|
|
||||||
// add length (in bits) into final pair of 32-bit integers (big-endian) [§5.1.1]
|
|
||||||
// note: most significant word would be (len-1)*8 >>> 32, but since JS converts
|
|
||||||
// bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
|
|
||||||
M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]);
|
|
||||||
M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;
|
|
||||||
|
|
||||||
// set initial hash value [§5.3.1]
|
|
||||||
var H0 = 0x67452301;
|
|
||||||
var H1 = 0xefcdab89;
|
|
||||||
var H2 = 0x98badcfe;
|
|
||||||
var H3 = 0x10325476;
|
|
||||||
var H4 = 0xc3d2e1f0;
|
|
||||||
|
|
||||||
// HASH COMPUTATION [§6.1.2]
|
|
||||||
|
|
||||||
var W = new Array(80); var a, b, c, d, e;
|
|
||||||
for (var i=0; i<N; i++) {
|
|
||||||
|
|
||||||
// 1 - prepare message schedule 'W'
|
|
||||||
for (var t=0; t<16; t++) W[t] = M[i][t];
|
|
||||||
for (var t=16; t<80; t++) W[t] = Sha1.ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
|
|
||||||
|
|
||||||
// 2 - initialise five working variables a, b, c, d, e with previous hash value
|
|
||||||
a = H0; b = H1; c = H2; d = H3; e = H4;
|
|
||||||
|
|
||||||
// 3 - main loop
|
|
||||||
for (var t=0; t<80; t++) {
|
|
||||||
var s = Math.floor(t/20); // seq for blocks of 'f' functions and 'K' constants
|
|
||||||
var T = (Sha1.ROTL(a,5) + Sha1.f(s,b,c,d) + e + K[s] + W[t]) & 0xffffffff;
|
|
||||||
e = d;
|
|
||||||
d = c;
|
|
||||||
c = Sha1.ROTL(b, 30);
|
|
||||||
b = a;
|
|
||||||
a = T;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4 - compute the new intermediate hash value (note 'addition modulo 2^32')
|
|
||||||
H0 = (H0+a) & 0xffffffff;
|
|
||||||
H1 = (H1+b) & 0xffffffff;
|
|
||||||
H2 = (H2+c) & 0xffffffff;
|
|
||||||
H3 = (H3+d) & 0xffffffff;
|
|
||||||
H4 = (H4+e) & 0xffffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Sha1.toHexStr(H0) + Sha1.toHexStr(H1) + Sha1.toHexStr(H2) +
|
|
||||||
Sha1.toHexStr(H3) + Sha1.toHexStr(H4);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function 'f' [§4.1.1].
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Sha1.f = function(s, x, y, z) {
|
|
||||||
switch (s) {
|
|
||||||
case 0: return (x & y) ^ (~x & z); // Ch()
|
|
||||||
case 1: return x ^ y ^ z; // Parity()
|
|
||||||
case 2: return (x & y) ^ (x & z) ^ (y & z); // Maj()
|
|
||||||
case 3: return x ^ y ^ z; // Parity()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rotates left (circular left shift) value x by n positions [§3.2.5].
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Sha1.ROTL = function(x, n) {
|
|
||||||
return (x<<n) | (x>>>(32-n));
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hexadecimal representation of a number.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
Sha1.toHexStr = function(n) {
|
|
||||||
// note can't use toString(16) as it is implementation-dependant,
|
|
||||||
// and in IE returns signed numbers when used on full words
|
|
||||||
var s="", v;
|
|
||||||
for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); }
|
|
||||||
return s;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
|
|
||||||
|
|
||||||
/** Extend String object with method to encode multi-byte string to utf8
|
|
||||||
* - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */
|
|
||||||
if (typeof String.prototype.utf8Encode == 'undefined') {
|
|
||||||
String.prototype.utf8Encode = function() {
|
|
||||||
return unescape( encodeURIComponent( this ) );
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Extend String object with method to decode utf8 string to multi-byte */
|
|
||||||
if (typeof String.prototype.utf8Decode == 'undefined') {
|
|
||||||
String.prototype.utf8Decode = function() {
|
|
||||||
try {
|
|
||||||
return decodeURIComponent( escape( this ) );
|
|
||||||
} catch (e) {
|
|
||||||
return this; // invalid UTF-8? return as-is
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
||||||
if (typeof module != 'undefined' && module.exports) module.exports = Sha1; // CommonJs export
|
|
||||||
if (typeof define == 'function' && define.amd) define([], function() { return Sha1; }); // AMD
|
|
||||||
|
|
||||||
export let hash = Sha1.hash;
|
|
@ -72,15 +72,9 @@ static void _file_read_read_callback(uv_fs_t* req)
|
|||||||
promiseid_t promise = (promiseid_t)(intptr_t)req->data;
|
promiseid_t promise = (promiseid_t)(intptr_t)req->data;
|
||||||
if (req->result >= 0)
|
if (req->result >= 0)
|
||||||
{
|
{
|
||||||
JSValue arrayBuffer = JS_NewArrayBufferCopy(context, (const uint8_t*)fsreq->buffer, req->result);
|
JSValue array = tf_util_new_uint8_array(context, (const uint8_t*)fsreq->buffer, req->result);
|
||||||
JSValue global = JS_GetGlobalObject(context);
|
tf_task_resolve_promise(task, promise, array);
|
||||||
JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array");
|
JS_FreeValue(context, array);
|
||||||
JSValue typedArray = JS_CallConstructor(context, constructor, 1, &arrayBuffer);
|
|
||||||
JS_FreeValue(context, constructor);
|
|
||||||
JS_FreeValue(context, global);
|
|
||||||
JS_FreeValue(context, arrayBuffer);
|
|
||||||
tf_task_resolve_promise(task, promise, typedArray);
|
|
||||||
JS_FreeValue(context, typedArray);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -823,25 +823,13 @@ void _socket_onRead(uv_stream_t* stream, ssize_t readSize, const uv_buf_t* buffe
|
|||||||
JS_FreeValue(context, ref);
|
JS_FreeValue(context, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _newUint8Array(JSContext* context, const void* data, size_t length)
|
|
||||||
{
|
|
||||||
JSValue arrayBuffer = JS_NewArrayBufferCopy(context, (const uint8_t*)data, length);
|
|
||||||
JSValue global = JS_GetGlobalObject(context);
|
|
||||||
JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array");
|
|
||||||
JSValue typedArray = JS_CallConstructor(context, constructor, 1, &arrayBuffer);
|
|
||||||
JS_FreeValue(context, constructor);
|
|
||||||
JS_FreeValue(context, global);
|
|
||||||
JS_FreeValue(context, arrayBuffer);
|
|
||||||
return typedArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _socket_notifyDataRead(socket_t* socket, const char* data, size_t length)
|
void _socket_notifyDataRead(socket_t* socket, const char* data, size_t length)
|
||||||
{
|
{
|
||||||
if (data && length > 0)
|
if (data && length > 0)
|
||||||
{
|
{
|
||||||
JSContext* context = tf_task_get_context(socket->_task);
|
JSContext* context = tf_task_get_context(socket->_task);
|
||||||
JSValue ref = JS_DupValue(context, socket->_object);
|
JSValue ref = JS_DupValue(context, socket->_object);
|
||||||
JSValue typedArray = _newUint8Array(context, data, length);
|
JSValue typedArray = tf_util_new_uint8_array(context, (const uint8_t*)data, length);
|
||||||
JSValue args[] = { typedArray };
|
JSValue args[] = { typedArray };
|
||||||
if (!JS_IsUndefined(socket->_onRead))
|
if (!JS_IsUndefined(socket->_onRead))
|
||||||
{
|
{
|
||||||
@ -1072,7 +1060,7 @@ JSValue _socket_getPeerCertificate(JSContext* context, JSValueConst this_val, in
|
|||||||
int result = tf_tls_session_get_peer_certificate(socket->_tls, buffer, sizeof(buffer));
|
int result = tf_tls_session_get_peer_certificate(socket->_tls, buffer, sizeof(buffer));
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
{
|
{
|
||||||
return _newUint8Array(tf_task_get_context(socket->_task), buffer, sizeof(buffer));
|
return tf_util_new_uint8_array(tf_task_get_context(socket->_task), (const uint8_t*)buffer, sizeof(buffer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
#include <base64c.h>
|
#include <base64c.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
#include <picohttpparser.h>
|
#include <picohttpparser.h>
|
||||||
#include <quickjs-libc.h>
|
#include <quickjs-libc.h>
|
||||||
#include <uv.h>
|
#include <uv.h>
|
||||||
@ -15,15 +17,9 @@ static JSValue _util_utf8_encode(JSContext* context, JSValueConst this_val, int
|
|||||||
{
|
{
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
const char* value = JS_ToCStringLen(context, &length, argv[0]);
|
const char* value = JS_ToCStringLen(context, &length, argv[0]);
|
||||||
JSValue arrayBuffer = JS_NewArrayBufferCopy(context, (const uint8_t*)value, length);
|
JSValue typed_array = tf_util_new_uint8_array(context, (const uint8_t*)value, length);
|
||||||
JSValue global = JS_GetGlobalObject(context);
|
|
||||||
JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array");
|
|
||||||
JS_FreeValue(context, global);
|
|
||||||
JSValue typedArray = JS_CallConstructor(context, constructor, 1, &arrayBuffer);
|
|
||||||
JS_FreeValue(context, constructor);
|
|
||||||
JS_FreeValue(context, arrayBuffer);
|
|
||||||
JS_FreeCString(context, value);
|
JS_FreeCString(context, value);
|
||||||
return typedArray;
|
return typed_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue _util_utf8_decode(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
static JSValue _util_utf8_decode(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
@ -70,17 +66,29 @@ static JSValue _util_base64_encode(JSContext* context, JSValueConst this_val, in
|
|||||||
{
|
{
|
||||||
JSValue result = JS_UNDEFINED;
|
JSValue result = JS_UNDEFINED;
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
|
uint8_t* array = tf_util_try_get_array_buffer(context, &length, argv[0]);
|
||||||
|
if (array)
|
||||||
|
{
|
||||||
|
char* encoded = tf_malloc(length * 4);
|
||||||
|
int r = base64c_encode(array, length, (uint8_t*)encoded, length * 4);
|
||||||
|
if (r >= 0)
|
||||||
|
{
|
||||||
|
result = JS_NewStringLen(context, encoded, r);
|
||||||
|
}
|
||||||
|
tf_free(encoded);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
const char* value = JS_ToCStringLen(context, &length, argv[0]);
|
const char* value = JS_ToCStringLen(context, &length, argv[0]);
|
||||||
char* encoded = tf_malloc(length * 4);
|
char* encoded = tf_malloc(length * 4);
|
||||||
|
|
||||||
int r = base64c_encode((const uint8_t*)value, length, (uint8_t*)encoded, length * 4);
|
int r = base64c_encode((const uint8_t*)value, length, (uint8_t*)encoded, length * 4);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
{
|
{
|
||||||
result = JS_NewStringLen(context, encoded, r);
|
result = JS_NewStringLen(context, encoded, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
tf_free(encoded);
|
tf_free(encoded);
|
||||||
JS_FreeCString(context, value);
|
JS_FreeCString(context, value);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +299,65 @@ static JSValue _util_parseHttp(JSContext* context, JSValueConst this_val, int ar
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue _util_sha1_digest(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
|
{
|
||||||
|
size_t length = 0;
|
||||||
|
const char* value = JS_ToCStringLen(context, &length, argv[0]);
|
||||||
|
unsigned char digest[SHA_DIGEST_LENGTH] = { 0 };
|
||||||
|
SHA1((const unsigned char*)value, length, digest);
|
||||||
|
return JS_NewArrayBufferCopy(context, digest, sizeof(digest));
|
||||||
|
}
|
||||||
|
|
||||||
|
JSValue tf_util_new_uint8_array(JSContext* context, const uint8_t* data, size_t size)
|
||||||
|
{
|
||||||
|
JSValue array_buffer = JS_NewArrayBufferCopy(context, data, size);
|
||||||
|
JSValue global = JS_GetGlobalObject(context);
|
||||||
|
JSValue constructor = JS_GetPropertyStr(context, global, "Uint8Array");
|
||||||
|
JSValue result = JS_CallConstructor(context, constructor, 1, &array_buffer);
|
||||||
|
JS_FreeValue(context, constructor);
|
||||||
|
JS_FreeValue(context, global);
|
||||||
|
JS_FreeValue(context, array_buffer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JSValue _util_mask_bytes(JSContext* context, JSValueConst this_val, int argc, JSValueConst* argv)
|
||||||
|
{
|
||||||
|
JSValue result = JS_UNDEFINED;
|
||||||
|
uint32_t mask = 0;
|
||||||
|
JS_ToUint32(context, &mask, argv[1]);
|
||||||
|
uint64_t double_mask = ((uint64_t)mask << 32) | mask;
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t length = 0;
|
||||||
|
size_t element_size = 0;
|
||||||
|
JSValue buffer = tf_util_try_get_typed_array_buffer(context, argv[0], &offset, &length, &element_size);
|
||||||
|
if (!JS_IsException(buffer))
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
const uint8_t* array = tf_util_try_get_array_buffer(context, &size, buffer);
|
||||||
|
if (array)
|
||||||
|
{
|
||||||
|
uint8_t* copy = tf_malloc(size);
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i + sizeof(double_mask) < size; i += sizeof(double_mask))
|
||||||
|
{
|
||||||
|
((uint64_t*)copy)[i / sizeof(double_mask)] = ((const uint64_t*)array)[i / sizeof(double_mask)] ^ double_mask;
|
||||||
|
}
|
||||||
|
for (; i + sizeof(mask) < size; i += sizeof(mask))
|
||||||
|
{
|
||||||
|
((uint32_t*)copy)[i / sizeof(mask)] = ((const uint32_t*)array)[i / sizeof(mask)] ^ mask;
|
||||||
|
}
|
||||||
|
for (; i < size; i++)
|
||||||
|
{
|
||||||
|
copy[i] = array[i] ^ ((mask >> (8 * (i % 4))) & 0xff);
|
||||||
|
}
|
||||||
|
result = tf_util_new_uint8_array(context, copy, size);
|
||||||
|
tf_free(copy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void tf_util_register(JSContext* context)
|
void tf_util_register(JSContext* context)
|
||||||
{
|
{
|
||||||
JSValue global = JS_GetGlobalObject(context);
|
JSValue global = JS_GetGlobalObject(context);
|
||||||
@ -301,6 +368,8 @@ void tf_util_register(JSContext* context)
|
|||||||
JS_SetPropertyStr(context, global, "print", JS_NewCFunction(context, _util_print, "print", 1));
|
JS_SetPropertyStr(context, global, "print", JS_NewCFunction(context, _util_print, "print", 1));
|
||||||
JS_SetPropertyStr(context, global, "setTimeout", JS_NewCFunction(context, _util_setTimeout, "setTimeout", 2));
|
JS_SetPropertyStr(context, global, "setTimeout", JS_NewCFunction(context, _util_setTimeout, "setTimeout", 2));
|
||||||
JS_SetPropertyStr(context, global, "parseHttp", JS_NewCFunction(context, _util_parseHttp, "parseHttp", 2));
|
JS_SetPropertyStr(context, global, "parseHttp", JS_NewCFunction(context, _util_parseHttp, "parseHttp", 2));
|
||||||
|
JS_SetPropertyStr(context, global, "sha1Digest", JS_NewCFunction(context, _util_sha1_digest, "sha1Digest", 1));
|
||||||
|
JS_SetPropertyStr(context, global, "maskBytes", JS_NewCFunction(context, _util_mask_bytes, "maskBytes", 2));
|
||||||
JS_FreeValue(context, global);
|
JS_FreeValue(context, global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,3 +11,4 @@ JSValue tf_util_try_get_typed_array_buffer(JSContext* context, JSValueConst obj,
|
|||||||
bool tf_util_report_error(JSContext* context, JSValue value);
|
bool tf_util_report_error(JSContext* context, JSValue value);
|
||||||
int tf_util_get_length(JSContext* context, JSValue value);
|
int tf_util_get_length(JSContext* context, JSValue value);
|
||||||
int tf_util_insert_index(const void* key, const void* base, size_t count, size_t size, int (*compare)(const void*, const void*));
|
int tf_util_insert_index(const void* key, const void* base, size_t count, size_t size, int (*compare)(const void*, const void*));
|
||||||
|
JSValue tf_util_new_uint8_array(JSContext* context, const uint8_t* data, size_t size);
|
||||||
|
Loading…
Reference in New Issue
Block a user