[wip] packaging nacl
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
{type, site}.
|
||||||
|
{realm, local}.
|
||||||
|
{name, jrw}.
|
||||||
|
{version, "0.1.0"}.
|
||||||
|
{deps, ["local-awcp-0.2.0"]}.
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
docs
|
||||||
|
erl_crash.dump
|
||||||
@@ -0,0 +1,482 @@
|
|||||||
|
TweetNaCl.js
|
||||||
|
============
|
||||||
|
|
||||||
|
Port of [TweetNaCl](http://tweetnacl.cr.yp.to) / [NaCl](http://nacl.cr.yp.to/)
|
||||||
|
to JavaScript for modern browsers and Node.js. Public domain.
|
||||||
|
|
||||||
|
[
|
||||||
|
](https://travis-ci.org/dchest/tweetnacl-js)
|
||||||
|
|
||||||
|
Demo: <https://dchest.github.io/tweetnacl-js/>
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
* [Overview](#overview)
|
||||||
|
* [Audits](#audits)
|
||||||
|
* [Installation](#installation)
|
||||||
|
* [Examples](#examples)
|
||||||
|
* [Usage](#usage)
|
||||||
|
* [Public-key authenticated encryption (box)](#public-key-authenticated-encryption-box)
|
||||||
|
* [Secret-key authenticated encryption (secretbox)](#secret-key-authenticated-encryption-secretbox)
|
||||||
|
* [Scalar multiplication](#scalar-multiplication)
|
||||||
|
* [Signatures](#signatures)
|
||||||
|
* [Hashing](#hashing)
|
||||||
|
* [Random bytes generation](#random-bytes-generation)
|
||||||
|
* [Constant-time comparison](#constant-time-comparison)
|
||||||
|
* [System requirements](#system-requirements)
|
||||||
|
* [Development and testing](#development-and-testing)
|
||||||
|
* [Benchmarks](#benchmarks)
|
||||||
|
* [Contributors](#contributors)
|
||||||
|
* [Who uses it](#who-uses-it)
|
||||||
|
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
The primary goal of this project is to produce a translation of TweetNaCl to
|
||||||
|
JavaScript which is as close as possible to the original C implementation, plus
|
||||||
|
a thin layer of idiomatic high-level API on top of it.
|
||||||
|
|
||||||
|
There are two versions, you can use either of them:
|
||||||
|
|
||||||
|
* `nacl.js` is the port of TweetNaCl with minimum differences from the
|
||||||
|
original + high-level API.
|
||||||
|
|
||||||
|
* `nacl-fast.js` is like `nacl.js`, but with some functions replaced with
|
||||||
|
faster versions. (Used by default when importing NPM package.)
|
||||||
|
|
||||||
|
|
||||||
|
Audits
|
||||||
|
------
|
||||||
|
|
||||||
|
TweetNaCl.js has been audited by [Cure53](https://cure53.de/) in January-February
|
||||||
|
2017 (audit was sponsored by [Deletype](https://deletype.com)):
|
||||||
|
|
||||||
|
> The overall outcome of this audit signals a particularly positive assessment
|
||||||
|
> for TweetNaCl-js, as the testing team was unable to find any security
|
||||||
|
> problems in the library.
|
||||||
|
|
||||||
|
[Read full audit report](https://cure53.de/tweetnacl.pdf)
|
||||||
|
|
||||||
|
While the audit didn't find any bugs, there has been [1 bug](https://github.com/dchest/tweetnacl-js/issues/187) discovered and fixed after the audit.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
You can install TweetNaCl.js via a package manager:
|
||||||
|
|
||||||
|
[Yarn](https://yarnpkg.com/):
|
||||||
|
|
||||||
|
$ yarn add tweetnacl
|
||||||
|
|
||||||
|
[NPM](https://www.npmjs.org/):
|
||||||
|
|
||||||
|
$ npm install tweetnacl
|
||||||
|
|
||||||
|
or [download source code](https://github.com/dchest/tweetnacl-js/releases).
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
You can find usage examples in our [wiki](https://github.com/dchest/tweetnacl-js/wiki/Examples).
|
||||||
|
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
All API functions accept and return bytes as `Uint8Array`s. If you need to
|
||||||
|
encode or decode strings, use functions from
|
||||||
|
<https://github.com/dchest/tweetnacl-util-js> or one of the more robust codec
|
||||||
|
packages.
|
||||||
|
|
||||||
|
In Node.js v4 and later `Buffer` objects are backed by `Uint8Array`s, so you
|
||||||
|
can freely pass them to TweetNaCl.js functions as arguments. The returned
|
||||||
|
objects are still `Uint8Array`s, so if you need `Buffer`s, you'll have to
|
||||||
|
convert them manually; make sure to convert using copying: `Buffer.from(array)`
|
||||||
|
(or `new Buffer(array)` in Node.js v4 or earlier), instead of sharing:
|
||||||
|
`Buffer.from(array.buffer)` (or `new Buffer(array.buffer)` Node 4 or earlier),
|
||||||
|
because some functions return subarrays of their buffers.
|
||||||
|
|
||||||
|
|
||||||
|
### Public-key authenticated encryption (box)
|
||||||
|
|
||||||
|
Implements *x25519-xsalsa20-poly1305*.
|
||||||
|
|
||||||
|
#### nacl.box.keyPair()
|
||||||
|
|
||||||
|
Generates a new random key pair for box and returns it as an object with
|
||||||
|
`publicKey` and `secretKey` members:
|
||||||
|
|
||||||
|
{
|
||||||
|
publicKey: ..., // Uint8Array with 32-byte public key
|
||||||
|
secretKey: ... // Uint8Array with 32-byte secret key
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#### nacl.box.keyPair.fromSecretKey(secretKey)
|
||||||
|
|
||||||
|
Returns a key pair for box with public key corresponding to the given secret
|
||||||
|
key.
|
||||||
|
|
||||||
|
#### nacl.box(message, nonce, theirPublicKey, mySecretKey)
|
||||||
|
|
||||||
|
Encrypts and authenticates message using peer's public key, our secret key, and
|
||||||
|
the given nonce, which must be unique for each distinct message for a key pair.
|
||||||
|
|
||||||
|
Returns an encrypted and authenticated message, which is
|
||||||
|
`nacl.box.overheadLength` longer than the original message.
|
||||||
|
|
||||||
|
#### nacl.box.open(box, nonce, theirPublicKey, mySecretKey)
|
||||||
|
|
||||||
|
Authenticates and decrypts the given box with peer's public key, our secret
|
||||||
|
key, and the given nonce.
|
||||||
|
|
||||||
|
Returns the original message, or `null` if authentication fails.
|
||||||
|
|
||||||
|
#### nacl.box.before(theirPublicKey, mySecretKey)
|
||||||
|
|
||||||
|
Returns a precomputed shared key which can be used in `nacl.box.after` and
|
||||||
|
`nacl.box.open.after`.
|
||||||
|
|
||||||
|
#### nacl.box.after(message, nonce, sharedKey)
|
||||||
|
|
||||||
|
Same as `nacl.box`, but uses a shared key precomputed with `nacl.box.before`.
|
||||||
|
|
||||||
|
#### nacl.box.open.after(box, nonce, sharedKey)
|
||||||
|
|
||||||
|
Same as `nacl.box.open`, but uses a shared key precomputed with `nacl.box.before`.
|
||||||
|
|
||||||
|
#### Constants
|
||||||
|
|
||||||
|
##### nacl.box.publicKeyLength = 32
|
||||||
|
|
||||||
|
Length of public key in bytes.
|
||||||
|
|
||||||
|
##### nacl.box.secretKeyLength = 32
|
||||||
|
|
||||||
|
Length of secret key in bytes.
|
||||||
|
|
||||||
|
##### nacl.box.sharedKeyLength = 32
|
||||||
|
|
||||||
|
Length of precomputed shared key in bytes.
|
||||||
|
|
||||||
|
##### nacl.box.nonceLength = 24
|
||||||
|
|
||||||
|
Length of nonce in bytes.
|
||||||
|
|
||||||
|
##### nacl.box.overheadLength = 16
|
||||||
|
|
||||||
|
Length of overhead added to box compared to original message.
|
||||||
|
|
||||||
|
|
||||||
|
### Secret-key authenticated encryption (secretbox)
|
||||||
|
|
||||||
|
Implements *xsalsa20-poly1305*.
|
||||||
|
|
||||||
|
#### nacl.secretbox(message, nonce, key)
|
||||||
|
|
||||||
|
Encrypts and authenticates message using the key and the nonce. The nonce must
|
||||||
|
be unique for each distinct message for this key.
|
||||||
|
|
||||||
|
Returns an encrypted and authenticated message, which is
|
||||||
|
`nacl.secretbox.overheadLength` longer than the original message.
|
||||||
|
|
||||||
|
#### nacl.secretbox.open(box, nonce, key)
|
||||||
|
|
||||||
|
Authenticates and decrypts the given secret box using the key and the nonce.
|
||||||
|
|
||||||
|
Returns the original message, or `null` if authentication fails.
|
||||||
|
|
||||||
|
#### Constants
|
||||||
|
|
||||||
|
##### nacl.secretbox.keyLength = 32
|
||||||
|
|
||||||
|
Length of key in bytes.
|
||||||
|
|
||||||
|
##### nacl.secretbox.nonceLength = 24
|
||||||
|
|
||||||
|
Length of nonce in bytes.
|
||||||
|
|
||||||
|
##### nacl.secretbox.overheadLength = 16
|
||||||
|
|
||||||
|
Length of overhead added to secret box compared to original message.
|
||||||
|
|
||||||
|
|
||||||
|
### Scalar multiplication
|
||||||
|
|
||||||
|
Implements *x25519*.
|
||||||
|
|
||||||
|
#### nacl.scalarMult(n, p)
|
||||||
|
|
||||||
|
Multiplies an integer `n` by a group element `p` and returns the resulting
|
||||||
|
group element.
|
||||||
|
|
||||||
|
#### nacl.scalarMult.base(n)
|
||||||
|
|
||||||
|
Multiplies an integer `n` by a standard group element and returns the resulting
|
||||||
|
group element.
|
||||||
|
|
||||||
|
#### Constants
|
||||||
|
|
||||||
|
##### nacl.scalarMult.scalarLength = 32
|
||||||
|
|
||||||
|
Length of scalar in bytes.
|
||||||
|
|
||||||
|
##### nacl.scalarMult.groupElementLength = 32
|
||||||
|
|
||||||
|
Length of group element in bytes.
|
||||||
|
|
||||||
|
|
||||||
|
### Signatures
|
||||||
|
|
||||||
|
Implements [ed25519](http://ed25519.cr.yp.to).
|
||||||
|
|
||||||
|
#### nacl.sign.keyPair()
|
||||||
|
|
||||||
|
Generates new random key pair for signing and returns it as an object with
|
||||||
|
`publicKey` and `secretKey` members:
|
||||||
|
|
||||||
|
{
|
||||||
|
publicKey: ..., // Uint8Array with 32-byte public key
|
||||||
|
secretKey: ... // Uint8Array with 64-byte secret key
|
||||||
|
}
|
||||||
|
|
||||||
|
#### nacl.sign.keyPair.fromSecretKey(secretKey)
|
||||||
|
|
||||||
|
Returns a signing key pair with public key corresponding to the given
|
||||||
|
64-byte secret key. The secret key must have been generated by
|
||||||
|
`nacl.sign.keyPair` or `nacl.sign.keyPair.fromSeed`.
|
||||||
|
|
||||||
|
#### nacl.sign.keyPair.fromSeed(seed)
|
||||||
|
|
||||||
|
Returns a new signing key pair generated deterministically from a 32-byte seed.
|
||||||
|
The seed must contain enough entropy to be secure. This method is not
|
||||||
|
recommended for general use: instead, use `nacl.sign.keyPair` to generate a new
|
||||||
|
key pair from a random seed.
|
||||||
|
|
||||||
|
#### nacl.sign(message, secretKey)
|
||||||
|
|
||||||
|
Signs the message using the secret key and returns a signed message.
|
||||||
|
|
||||||
|
#### nacl.sign.open(signedMessage, publicKey)
|
||||||
|
|
||||||
|
Verifies the signed message and returns the message without signature.
|
||||||
|
|
||||||
|
Returns `null` if verification failed.
|
||||||
|
|
||||||
|
#### nacl.sign.detached(message, secretKey)
|
||||||
|
|
||||||
|
Signs the message using the secret key and returns a signature.
|
||||||
|
|
||||||
|
#### nacl.sign.detached.verify(message, signature, publicKey)
|
||||||
|
|
||||||
|
Verifies the signature for the message and returns `true` if verification
|
||||||
|
succeeded or `false` if it failed.
|
||||||
|
|
||||||
|
#### Constants
|
||||||
|
|
||||||
|
##### nacl.sign.publicKeyLength = 32
|
||||||
|
|
||||||
|
Length of signing public key in bytes.
|
||||||
|
|
||||||
|
##### nacl.sign.secretKeyLength = 64
|
||||||
|
|
||||||
|
Length of signing secret key in bytes.
|
||||||
|
|
||||||
|
##### nacl.sign.seedLength = 32
|
||||||
|
|
||||||
|
Length of seed for `nacl.sign.keyPair.fromSeed` in bytes.
|
||||||
|
|
||||||
|
##### nacl.sign.signatureLength = 64
|
||||||
|
|
||||||
|
Length of signature in bytes.
|
||||||
|
|
||||||
|
|
||||||
|
### Hashing
|
||||||
|
|
||||||
|
Implements *SHA-512*.
|
||||||
|
|
||||||
|
#### nacl.hash(message)
|
||||||
|
|
||||||
|
Returns SHA-512 hash of the message.
|
||||||
|
|
||||||
|
#### Constants
|
||||||
|
|
||||||
|
##### nacl.hash.hashLength = 64
|
||||||
|
|
||||||
|
Length of hash in bytes.
|
||||||
|
|
||||||
|
|
||||||
|
### Random bytes generation
|
||||||
|
|
||||||
|
#### nacl.randomBytes(length)
|
||||||
|
|
||||||
|
Returns a `Uint8Array` of the given length containing random bytes of
|
||||||
|
cryptographic quality.
|
||||||
|
|
||||||
|
**Implementation note**
|
||||||
|
|
||||||
|
TweetNaCl.js uses the following methods to generate random bytes,
|
||||||
|
depending on the platform it runs on:
|
||||||
|
|
||||||
|
* `window.crypto.getRandomValues` (WebCrypto standard)
|
||||||
|
* `window.msCrypto.getRandomValues` (Internet Explorer 11)
|
||||||
|
* `crypto.randomBytes` (Node.js)
|
||||||
|
|
||||||
|
If the platform doesn't provide a suitable PRNG, the following functions,
|
||||||
|
which require random numbers, will throw exception:
|
||||||
|
|
||||||
|
* `nacl.randomBytes`
|
||||||
|
* `nacl.box.keyPair`
|
||||||
|
* `nacl.sign.keyPair`
|
||||||
|
|
||||||
|
Other functions are deterministic and will continue working.
|
||||||
|
|
||||||
|
If a platform you are targeting doesn't implement secure random number
|
||||||
|
generator, but you somehow have a cryptographically-strong source of entropy
|
||||||
|
(not `Math.random`!), and you know what you are doing, you can plug it into
|
||||||
|
TweetNaCl.js like this:
|
||||||
|
|
||||||
|
nacl.setPRNG(function(x, n) {
|
||||||
|
// ... copy n random bytes into x ...
|
||||||
|
});
|
||||||
|
|
||||||
|
Note that `nacl.setPRNG` *completely replaces* internal random byte generator
|
||||||
|
with the one provided.
|
||||||
|
|
||||||
|
|
||||||
|
### Constant-time comparison
|
||||||
|
|
||||||
|
#### nacl.verify(x, y)
|
||||||
|
|
||||||
|
Compares `x` and `y` in constant time and returns `true` if their lengths are
|
||||||
|
non-zero and equal, and their contents are equal.
|
||||||
|
|
||||||
|
Returns `false` if either of the arguments has zero length, or arguments have
|
||||||
|
different lengths, or their contents differ.
|
||||||
|
|
||||||
|
|
||||||
|
System requirements
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
TweetNaCl.js supports modern browsers that have a cryptographically secure
|
||||||
|
pseudorandom number generator and typed arrays, including the latest versions
|
||||||
|
of:
|
||||||
|
|
||||||
|
* Chrome
|
||||||
|
* Firefox
|
||||||
|
* Safari (Mac, iOS)
|
||||||
|
* Internet Explorer 11
|
||||||
|
|
||||||
|
Other systems:
|
||||||
|
|
||||||
|
* Node.js
|
||||||
|
|
||||||
|
|
||||||
|
Development and testing
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Install NPM modules needed for development:
|
||||||
|
|
||||||
|
$ npm install
|
||||||
|
|
||||||
|
To build minified versions:
|
||||||
|
|
||||||
|
$ npm run build
|
||||||
|
|
||||||
|
Tests use minified version, so make sure to rebuild it every time you change
|
||||||
|
`nacl.js` or `nacl-fast.js`.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
To run tests in Node.js:
|
||||||
|
|
||||||
|
$ npm run test-node
|
||||||
|
|
||||||
|
By default all tests described here work on `nacl.min.js`. To test other
|
||||||
|
versions, set environment variable `NACL_SRC` to the file name you want to test.
|
||||||
|
For example, the following command will test fast minified version:
|
||||||
|
|
||||||
|
$ NACL_SRC=nacl-fast.min.js npm run test-node
|
||||||
|
|
||||||
|
To run full suite of tests in Node.js, including comparing outputs of
|
||||||
|
JavaScript port to outputs of the original C version:
|
||||||
|
|
||||||
|
$ npm run test-node-all
|
||||||
|
|
||||||
|
To prepare tests for browsers:
|
||||||
|
|
||||||
|
$ npm run build-test-browser
|
||||||
|
|
||||||
|
and then open `test/browser/test.html` (or `test/browser/test-fast.html`) to
|
||||||
|
run them.
|
||||||
|
|
||||||
|
To run tests in both Node and Electron:
|
||||||
|
|
||||||
|
$ npm test
|
||||||
|
|
||||||
|
### Benchmarking
|
||||||
|
|
||||||
|
To run benchmarks in Node.js:
|
||||||
|
|
||||||
|
$ npm run bench
|
||||||
|
$ NACL_SRC=nacl-fast.min.js npm run bench
|
||||||
|
|
||||||
|
To run benchmarks in a browser, open `test/benchmark/bench.html` (or
|
||||||
|
`test/benchmark/bench-fast.html`).
|
||||||
|
|
||||||
|
|
||||||
|
Benchmarks
|
||||||
|
----------
|
||||||
|
|
||||||
|
For reference, here are benchmarks from MacBook Pro (Retina, 13-inch, Mid 2014)
|
||||||
|
laptop with 2.6 GHz Intel Core i5 CPU (Intel) in Chrome 53/OS X, Xiaomi Redmi
|
||||||
|
Note 3 smartphone with 1.8 GHz Qualcomm Snapdragon 650 64-bit CPU (ARM) in
|
||||||
|
Chrome 52/Android, and MacBook Air 2020 with Apple M1 SOC (M1) in Chromium 102/macOS.
|
||||||
|
|
||||||
|
| | nacl.js Intel | nacl-fast.js Intel | nacl.js ARM | nacl-fast.js ARM | nacl-fast.js M1 |
|
||||||
|
| ------------- |:-------------:|:-------------------:|:-------------:|:-----------------:|:-----------------:|
|
||||||
|
| salsa20 | 1.3 MB/s | 128 MB/s | 0.4 MB/s | 43 MB/s | 268 MB/s |
|
||||||
|
| poly1305 | 13 MB/s | 171 MB/s | 4 MB/s | 52 MB/s | 248 MB/s |
|
||||||
|
| hash | 4 MB/s | 34 MB/s | 0.9 MB/s | 12 MB/s | 76 MB/s |
|
||||||
|
| secretbox 1K | 1113 op/s | 57583 op/s | 334 op/s | 14227 op/s | 54546 op/s |
|
||||||
|
| box 1K | 145 op/s | 718 op/s | 37 op/s | 368 op/s | 1836 op/s |
|
||||||
|
| scalarMult | 171 op/s | 733 op/s | 56 op/s | 380 op/s | 1882 op/s |
|
||||||
|
| sign | 77 op/s | 200 op/s | 20 op/s | 61 op/s | 592 op/s |
|
||||||
|
| sign.open | 39 op/s | 102 op/s | 11 op/s | 31 op/s | 300 op/s |
|
||||||
|
|
||||||
|
(You can run benchmarks on your devices by clicking on the links at the bottom
|
||||||
|
of the [home page](https://tweetnacl.js.org)).
|
||||||
|
|
||||||
|
In short, with *nacl-fast.js* and 1024-byte messages you can expect to encrypt and
|
||||||
|
authenticate more than 57000 messages per second on a typical laptop or more than
|
||||||
|
14000 messages per second on a $170 smartphone, sign about 500 and verify 300
|
||||||
|
messages per second on a laptop or 60 and 30 messages per second on a smartphone,
|
||||||
|
per CPU core (with Web Workers you can do these operations in parallel),
|
||||||
|
which is good enough for most applications.
|
||||||
|
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
------------
|
||||||
|
|
||||||
|
See AUTHORS.md file.
|
||||||
|
|
||||||
|
|
||||||
|
Third-party libraries based on TweetNaCl.js
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
* [chloride](https://github.com/dominictarr/chloride) - unified API for various NaCl modules
|
||||||
|
* [forward-secrecy](https://github.com/alax/forward-secrecy) — Axolotl ratchet implementation
|
||||||
|
* [nacl-stream](https://github.com/dchest/nacl-stream-js) - streaming encryption
|
||||||
|
* [ristretto255-js](https://github.com/calibra/ristretto255-js) — implementation of the [ristretto255 group](https://ristretto.group/)
|
||||||
|
* [tweetnacl-auth-js](https://github.com/dchest/tweetnacl-auth-js) — implementation of [`crypto_auth`](http://nacl.cr.yp.to/auth.html)
|
||||||
|
* [tweetnacl-js-sealed-box](https://github.com/TogaTech/tweetnacl-js-sealed-box) — fork that adds [`sealed boxes`](https://download.libsodium.org/doc/public-key_cryptography/sealed_boxes.html)
|
||||||
|
* [ed2curve](https://github.com/dchest/ed2curve-js) — convert Ed25519 signing key pair to X25519 boxes key pair
|
||||||
|
|
||||||
|
|
||||||
|
Who uses it
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Some notable users of TweetNaCl.js are listed on the [associated wiki page](https://github.com/dchest/tweetnacl-js/wiki/Who-uses-TweetNaCl.js).
|
||||||
Vendored
+98
@@ -0,0 +1,98 @@
|
|||||||
|
// Type definitions for TweetNaCl.js
|
||||||
|
|
||||||
|
export as namespace nacl;
|
||||||
|
|
||||||
|
declare var nacl: nacl;
|
||||||
|
export = nacl;
|
||||||
|
|
||||||
|
declare namespace nacl {
|
||||||
|
export interface BoxKeyPair {
|
||||||
|
publicKey: Uint8Array;
|
||||||
|
secretKey: Uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SignKeyPair {
|
||||||
|
publicKey: Uint8Array;
|
||||||
|
secretKey: Uint8Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface secretbox {
|
||||||
|
(msg: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;
|
||||||
|
open(box: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array | null;
|
||||||
|
readonly keyLength: number;
|
||||||
|
readonly nonceLength: number;
|
||||||
|
readonly overheadLength: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface scalarMult {
|
||||||
|
(n: Uint8Array, p: Uint8Array): Uint8Array;
|
||||||
|
base(n: Uint8Array): Uint8Array;
|
||||||
|
readonly scalarLength: number;
|
||||||
|
readonly groupElementLength: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace boxProps {
|
||||||
|
export interface open {
|
||||||
|
(msg: Uint8Array, nonce: Uint8Array, publicKey: Uint8Array, secretKey: Uint8Array): Uint8Array | null;
|
||||||
|
after(box: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface keyPair {
|
||||||
|
(): BoxKeyPair;
|
||||||
|
fromSecretKey(secretKey: Uint8Array): BoxKeyPair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface box {
|
||||||
|
(msg: Uint8Array, nonce: Uint8Array, publicKey: Uint8Array, secretKey: Uint8Array): Uint8Array;
|
||||||
|
before(publicKey: Uint8Array, secretKey: Uint8Array): Uint8Array;
|
||||||
|
after(msg: Uint8Array, nonce: Uint8Array, key: Uint8Array): Uint8Array;
|
||||||
|
open: boxProps.open;
|
||||||
|
keyPair: boxProps.keyPair;
|
||||||
|
readonly publicKeyLength: number;
|
||||||
|
readonly secretKeyLength: number;
|
||||||
|
readonly sharedKeyLength: number;
|
||||||
|
readonly nonceLength: number;
|
||||||
|
readonly overheadLength: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace signProps {
|
||||||
|
export interface detached {
|
||||||
|
(msg: Uint8Array, secretKey: Uint8Array): Uint8Array;
|
||||||
|
verify(msg: Uint8Array, sig: Uint8Array, publicKey: Uint8Array): boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface keyPair {
|
||||||
|
(): SignKeyPair;
|
||||||
|
fromSecretKey(secretKey: Uint8Array): SignKeyPair;
|
||||||
|
fromSeed(secretKey: Uint8Array): SignKeyPair;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface sign {
|
||||||
|
(msg: Uint8Array, secretKey: Uint8Array): Uint8Array;
|
||||||
|
open(signedMsg: Uint8Array, publicKey: Uint8Array): Uint8Array | null;
|
||||||
|
detached: signProps.detached;
|
||||||
|
keyPair: signProps.keyPair;
|
||||||
|
readonly publicKeyLength: number;
|
||||||
|
readonly secretKeyLength: number;
|
||||||
|
readonly seedLength: number;
|
||||||
|
readonly signatureLength: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface hash {
|
||||||
|
(msg: Uint8Array): Uint8Array;
|
||||||
|
readonly hashLength: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface nacl {
|
||||||
|
randomBytes(n: number): Uint8Array;
|
||||||
|
secretbox: nacl.secretbox;
|
||||||
|
scalarMult: nacl.scalarMult;
|
||||||
|
box: nacl.box;
|
||||||
|
sign: nacl.sign;
|
||||||
|
hash: nacl.hash;
|
||||||
|
verify(x: Uint8Array, y: Uint8Array): boolean;
|
||||||
|
setPRNG(fn: (x: Uint8Array, n: number) => void): void;
|
||||||
|
}
|
||||||
Vendored
+1178
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
|||||||
|
{type, external}.
|
||||||
|
{realm, local}.
|
||||||
|
{name, tweetnacl}.
|
||||||
|
{version, "1.0.3"}.
|
||||||
|
{deps, []}.
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{"compilerOptions" : {"target" : "es2022",
|
||||||
|
"strict" : true,
|
||||||
|
"esModuleInterop" : true,
|
||||||
|
"skipLibCheck" : true,
|
||||||
|
"forceConsistentCasingInFileNames" : true,
|
||||||
|
"noImplicitAny" : true,
|
||||||
|
"strictNullChecks" : true,
|
||||||
|
"strictPropertyInitialization" : true,
|
||||||
|
"sourceMap" : true,
|
||||||
|
"outDir" : "dist",
|
||||||
|
"declaration" : true},
|
||||||
|
"$schema" : "https://json.schemastore.org/tsconfig",
|
||||||
|
"display" : "Recommended",
|
||||||
|
"include" : ["src/**/*"],
|
||||||
|
"exclude" : ["src/jx_include"],
|
||||||
|
"composite" : true}
|
||||||
+47
-254
@@ -1,267 +1,60 @@
|
|||||||
=====================================================================
|
INTRODUCTION
|
||||||
tl;dr
|
Jex is a simple packaging/dependency system for TypeScript/JavaScript
|
||||||
=====================================================================
|
projects.
|
||||||
|
|
||||||
You can get this by running jex --help
|
As of now, Jex is a glorified shell script that automates a lot of the
|
||||||
|
tedium in building sidekick, JR, etc. Jex is very much a work in progress,
|
||||||
|
so these instructions are subject to change.
|
||||||
|
|
||||||
COMMANDS:
|
Jex is currently hyper-specialized to our use cases inside of Vanillae, and
|
||||||
man show the manual
|
is probably (currently) unsuitable for your use case. For instance, Jex
|
||||||
dwim- init, pull, build
|
assumes you are running a UNIX-like system with standard UNIX programs
|
||||||
dwim+ init, pull, build, mindist, push
|
installed (e.g. tree, rsync, tar, etc). It also makes very strong
|
||||||
cfgbarf barf out the jex.eterms file (mostly to make sure it parses correctly)
|
assumptions about your project structure and how you want to distribute
|
||||||
echo home echo $HOME
|
your project.
|
||||||
echo jexdir echo $HOME/.jex
|
|
||||||
echo devdir echo $HOME/.jex/dev
|
|
||||||
echo pkgname name of current package
|
|
||||||
echo pkgdir echo $HOME/.jex/dev/realm-name-X.Y.Z
|
|
||||||
echo deps list dependencies of current package
|
|
||||||
echo pathof PKG list the path to PKG or
|
|
||||||
init mkdir -p $HOME/.jex/dev
|
|
||||||
build tsc && cp -r ./src/jex_include ./dist/
|
|
||||||
-w, --weak continue building even if tsc fails
|
|
||||||
-f, --force use cp -rf instead of cp -r
|
|
||||||
mindist mkdir jex_mindist && cp -r src jex_mindist && cp -r dist jex_mindist && rm -r jex_mindist/src/jex_include
|
|
||||||
-f, --force use cp -rf instead of cp -r
|
|
||||||
push rsync -a jex_mindist/ PKGDIR
|
|
||||||
ls ls $HOME/.jex/dev
|
|
||||||
tree tree $HOME/.jex/
|
|
||||||
rmpkg PKG rm -r $HOME/.jex/dev/PKG
|
|
||||||
pull pull each dependency into src/jx_include
|
|
||||||
|
|
||||||
|
Our long-term goal is to build Jex out into a proper secure packaging
|
||||||
|
system, and completely remove any dependency on NPM. NPM comes with a lot
|
||||||
|
of unfixable security issues that present an unacceptable risk in a
|
||||||
|
business context. Developing software for the business context is the
|
||||||
|
focus of the Vanillae project.
|
||||||
|
|
||||||
=====================================================================
|
jex.eterms CONFIG FILE
|
||||||
JEX MANUAL
|
Every project requires a file called `jex.eterms` in the root of the
|
||||||
=====================================================================
|
project.
|
||||||
|
|
||||||
Jex is a simple packaging/dependency system for TypeScript/JavaScript
|
The config file is a list of Erlang terms separated by `.`s
|
||||||
projects.
|
|
||||||
|
|
||||||
As of now, Jex is a glorified shell script that automates a lot of
|
The following keys must exist, the rest are ignored
|
||||||
the tedium in building sidekick, JR, etc. Jex is very much a work in
|
|
||||||
progress, so these instructions are subject to change.
|
|
||||||
|
|
||||||
Jex is currently hyper-specialized to our use cases inside of
|
{type, library | external | extension}.
|
||||||
Vanillae, and is probably (currently) unsuitable for your use case.
|
This key implies other settings in the build process
|
||||||
For instance, Jex assumes you are running a UNIX-like system with
|
|
||||||
standard UNIX programs installed (e.g. tree, rsync, tar, etc). It
|
|
||||||
also makes very strong assumptions about your project structure and
|
|
||||||
how you want to distribute your project.
|
|
||||||
|
|
||||||
Our long-term goal is to build Jex out into a proper secure packaging
|
library ->
|
||||||
system, and completely remove any dependency on NPM. NPM comes with
|
The standard option. Pulls in dependencies and builds them,
|
||||||
a lot of unfixable security issues that present an unacceptable risk
|
assuming normal project layout. This is what you want in most
|
||||||
in a business context. Developing software for the business context
|
cases, even for things that are not libraries.
|
||||||
is the focus of the Vanillae project.
|
|
||||||
|
|
||||||
You'll see how it works and what the philosophy is if you keep
|
external ->
|
||||||
reading.
|
This is for external pre-built packages that we didn't develop,
|
||||||
|
such as TweetNaCl. This does not run `tsc`, etc. Jex assumes
|
||||||
|
the project has already been built, and so "install" etc just
|
||||||
|
copies stuff.
|
||||||
|
|
||||||
|
extension ->
|
||||||
|
Used for Jack Russell. Extensions have a much more complicated
|
||||||
|
build process because there are three different execution
|
||||||
|
contexts with three different constraint sets.
|
||||||
|
|
||||||
=====================================================================
|
{realm, atom()}.
|
||||||
HOW IT WORKS
|
{name, atom()}.
|
||||||
=====================================================================
|
{version, string()}.
|
||||||
|
{deps, [string()]}.
|
||||||
|
|
||||||
To start off, we run `jex init`
|
PROJECT STRUCTURE
|
||||||
|
Jex makes very strong assumptions about your project structure
|
||||||
|
|
||||||
[~] % jex init
|
README.md used by documentation tool `typedoc`
|
||||||
$ mkdir -p /home/pharpend/.jex/dev
|
jex.eterms explained above
|
||||||
|
tsconfig.json needed for tsc
|
||||||
As I said above, jex is currently a glorified shell script. Much like
|
src/ typescript source code
|
||||||
`make`, jex prints the command it's running with a `$` at the
|
|
||||||
beginning of the line.
|
|
||||||
|
|
||||||
We can get a sense of what will go in this directory by running `jex
|
|
||||||
tree` (yours will not look like this):
|
|
||||||
|
|
||||||
[~] % jex tree
|
|
||||||
$ tree /home/pharpend/.jex
|
|
||||||
/home/pharpend/.jex
|
|
||||||
└── dev
|
|
||||||
├── local-awcp-0.1.0
|
|
||||||
│ ├── dist
|
|
||||||
│ │ ├── awcp.d.ts
|
|
||||||
│ │ ├── awcp.js
|
|
||||||
│ │ ├── awcp.js.map
|
|
||||||
│ │ └── jex_include
|
|
||||||
│ └── src
|
|
||||||
│ └── awcp.ts
|
|
||||||
├── local-parasite-0.1.0
|
|
||||||
│ ├── dist
|
|
||||||
│ │ ├── ae_compiler.d.ts
|
|
||||||
│ │ ├── ae_compiler.js
|
|
||||||
│ │ ├── ae_compiler.js.map
|
|
||||||
│ │ ├── ae_node.d.ts
|
|
||||||
│ │ ├── ae_node.js
|
|
||||||
│ │ ├── ae_node.js.map
|
|
||||||
│ │ ├── jex_include
|
|
||||||
│ │ ├── net.d.ts
|
|
||||||
│ │ ├── net.js
|
|
||||||
│ │ └── net.js.map
|
|
||||||
│ └── src
|
|
||||||
│ ├── ae_compiler.ts
|
|
||||||
│ ├── ae_node.ts
|
|
||||||
│ └── net.ts
|
|
||||||
└── local-sidekick-0.1.0
|
|
||||||
├── dist
|
|
||||||
│ ├── jex_include
|
|
||||||
│ │ └── local-awcp-0.1.0
|
|
||||||
│ │ ├── dist
|
|
||||||
│ │ │ ├── awcp.d.ts
|
|
||||||
│ │ │ ├── awcp.js
|
|
||||||
│ │ │ ├── awcp.js.map
|
|
||||||
│ │ │ └── jex_include
|
|
||||||
│ │ └── src
|
|
||||||
│ │ └── awcp.ts
|
|
||||||
│ ├── sidekick.d.ts
|
|
||||||
│ ├── sidekick.js
|
|
||||||
│ └── sidekick.js.map
|
|
||||||
└── src
|
|
||||||
└── sidekick.ts
|
|
||||||
|
|
||||||
17 directories, 24 files
|
|
||||||
|
|
||||||
Currently, Jex is managing 3 packages for me:
|
|
||||||
|
|
||||||
1. awcp
|
|
||||||
2. parasite
|
|
||||||
3. sidekick
|
|
||||||
|
|
||||||
In a secure context, we want to avoid opaque rewrites whenever
|
|
||||||
possible. This rules out bundling or minifying tools such as
|
|
||||||
browserify. We want the code that is running in the user's browser
|
|
||||||
to be human-readable and to have a straightforward mapping to
|
|
||||||
the original source.
|
|
||||||
|
|
||||||
Let's start with the simplest package which is `awcp`. This is the
|
|
||||||
source directory listing
|
|
||||||
|
|
||||||
[v/libs pharpend/develop] % tree awcp
|
|
||||||
awcp
|
|
||||||
├── dist
|
|
||||||
│ ├── awcp.d.ts
|
|
||||||
│ ├── awcp.js
|
|
||||||
│ ├── awcp.js.map
|
|
||||||
│ └── jex_include
|
|
||||||
├── erl_crash.dump
|
|
||||||
├── jex.eterms
|
|
||||||
├── jex_mindist
|
|
||||||
│ ├── dist
|
|
||||||
│ │ ├── awcp.d.ts
|
|
||||||
│ │ ├── awcp.js
|
|
||||||
│ │ ├── awcp.js.map
|
|
||||||
│ │ └── jex_include
|
|
||||||
│ └── src
|
|
||||||
│ └── awcp.ts
|
|
||||||
├── LICENSE
|
|
||||||
├── Makefile
|
|
||||||
├── README.md
|
|
||||||
├── src
|
|
||||||
│ ├── awcp.ts
|
|
||||||
│ └── jex_include
|
|
||||||
└── tsconfig.json
|
|
||||||
|
|
||||||
8 directories, 14 files
|
|
||||||
|
|
||||||
There is only one source file: `/src/awcp.ts`. There is a directory
|
|
||||||
called `/src/jex_include/` which is empty. If awcp had dependencies,
|
|
||||||
this is where they would go.
|
|
||||||
|
|
||||||
The file tree that ends up in `~/.jex/dev` is the `jex_mindist`
|
|
||||||
directory. Let's focus on that
|
|
||||||
|
|
||||||
[v/libs pharpend/develop] % tree awcp/jex_mindist
|
|
||||||
awcp/jex_mindist
|
|
||||||
├── dist
|
|
||||||
│ ├── awcp.d.ts
|
|
||||||
│ ├── awcp.js
|
|
||||||
│ ├── awcp.js.map
|
|
||||||
│ └── jex_include
|
|
||||||
└── src
|
|
||||||
└── awcp.ts
|
|
||||||
|
|
||||||
3 directories, 4 files
|
|
||||||
|
|
||||||
As you can see, it's the same tree
|
|
||||||
|
|
||||||
[v/libs pharpend/develop] % tree ~/.jex/dev/local-awcp-0.1.0
|
|
||||||
/home/pharpend/.jex/dev/local-awcp-0.1.0
|
|
||||||
├── dist
|
|
||||||
│ ├── awcp.d.ts
|
|
||||||
│ ├── awcp.js
|
|
||||||
│ ├── awcp.js.map
|
|
||||||
│ └── jex_include
|
|
||||||
└── src
|
|
||||||
└── awcp.ts
|
|
||||||
|
|
||||||
3 directories, 4 files
|
|
||||||
|
|
||||||
Briefly, jex is built around the assumptions that you want simplicity,
|
|
||||||
transparency, and composability, possibly at the expense of some
|
|
||||||
duplication.
|
|
||||||
|
|
||||||
It's assumed that you are developing JS to execute in the context of
|
|
||||||
a website, that you are writing only a small amount of JS (i.e. NOT
|
|
||||||
framework JS or a single-page-application), and that serving a
|
|
||||||
JavaScript file tree does not present a bandwidth issue. Everything
|
|
||||||
has a version number, so that you can properly take advantage of
|
|
||||||
caching.
|
|
||||||
|
|
||||||
The idea is that you want to be able to take that file tree above,
|
|
||||||
make it into a tarball, drop it on your server, and have it "just
|
|
||||||
work". Or, you can drop the whole tree into your existing project
|
|
||||||
and have it "just work". We want the source map to work properly, so
|
|
||||||
the TypeScript source is included in the bundle.
|
|
||||||
|
|
||||||
For more context, let's switch over to the Sidekick project. Sidekick
|
|
||||||
depends on AWCP.
|
|
||||||
|
|
||||||
[src/v pharpend/develop] % tree sidekick/src
|
|
||||||
sidekick/src
|
|
||||||
├── jex_include
|
|
||||||
│ └── local-awcp-0.1.0
|
|
||||||
│ ├── dist
|
|
||||||
│ │ ├── awcp.d.ts
|
|
||||||
│ │ ├── awcp.js
|
|
||||||
│ │ ├── awcp.js.map
|
|
||||||
│ │ └── jex_include
|
|
||||||
│ └── src
|
|
||||||
│ └── awcp.ts
|
|
||||||
└── sidekick.ts
|
|
||||||
|
|
||||||
5 directories, 5 files
|
|
||||||
|
|
||||||
Jex automates the process of pulling awcp from the local repository
|
|
||||||
and including it in a predictable file path in the source tree.
|
|
||||||
|
|
||||||
To import AWCP, `sidekick.ts` contains this line
|
|
||||||
|
|
||||||
import * as awcp from './jex_include/local-awcp-0.1.0/dist/awcp.js';
|
|
||||||
|
|
||||||
Notice that we're importing the JS file, not the TS file. TypeScript
|
|
||||||
gets its type information from the `dist/awcp.d.ts` file, not from
|
|
||||||
the `src/awcp.ts` file. The `src/awcp.ts` file is only included so
|
|
||||||
the source map works properly in the browser's debugger.
|
|
||||||
|
|
||||||
The next step is to compile sidekick. To do this, we run `jex dwim-`.
|
|
||||||
This is shorthand for `jex init && jex pull && jex build`
|
|
||||||
|
|
||||||
dwim(minus) ->
|
|
||||||
% make the ~/.jex/dev directory
|
|
||||||
init(),
|
|
||||||
% pull the dependencies into src/jex_include
|
|
||||||
pull(),
|
|
||||||
% run tsc
|
|
||||||
build([]);
|
|
||||||
dwim(plus) ->
|
|
||||||
dwim(minus),
|
|
||||||
% make the jex_mindist folder
|
|
||||||
mindist([]),
|
|
||||||
% push to local repo
|
|
||||||
push().
|
|
||||||
|
|
||||||
This is the essential flow of using Jex. Suppose we update AWCP and
|
|
||||||
want to see that result reflected in sidekick.
|
|
||||||
|
|
||||||
1. In the AWCP repository, we run `jex dwim+`. This makes a new
|
|
||||||
distribution tarball and pushes it to the local repository.
|
|
||||||
2. In the sidekick repository, we run `jex dwim-`. This pulls the new
|
|
||||||
|
|||||||
+41
-3
@@ -40,6 +40,10 @@ help() ->
|
|||||||
% TODONE: jex get_mindist PKG
|
% TODONE: jex get_mindist PKG
|
||||||
% TODONE: jex dwim++ = install
|
% TODONE: jex dwim++ = install
|
||||||
|
|
||||||
|
% TODO: jex directory based on version
|
||||||
|
% TODO: "external" install
|
||||||
|
% - pull only on library
|
||||||
|
|
||||||
% TODO: use less than full qualified names (not priority)
|
% TODO: use less than full qualified names (not priority)
|
||||||
% TODO: --name option for docs (not priority)
|
% TODO: --name option for docs (not priority)
|
||||||
% TODO: make fulldist for arbitrary installed package (requires storing jex.eterms, not hard but also not a priority)
|
% TODO: make fulldist for arbitrary installed package (requires storing jex.eterms, not hard but also not a priority)
|
||||||
@@ -183,11 +187,45 @@ dwim(plus_plus) ->
|
|||||||
%%-----------------------------------------------------------------------------
|
%%-----------------------------------------------------------------------------
|
||||||
|
|
||||||
cfgbarf() ->
|
cfgbarf() ->
|
||||||
tell(info, "~tp~n", [file:consult("jex.eterms")]).
|
tell(info, "~tp~n", [cfg(unsafe)]).
|
||||||
|
|
||||||
|
|
||||||
cfg() ->
|
cfg() ->
|
||||||
file:consult("jex.eterms").
|
cfg(safe).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec cfg(MaybeSafe) -> Result
|
||||||
|
when MaybeSafe :: safe | unsafe
|
||||||
|
Result :: {ok, Cfg :: proplist()}
|
||||||
|
| {error, Reason :: term()}.
|
||||||
|
% @doc "safe" means it checks to make sure the
|
||||||
|
|
||||||
|
cfg(unsafe) ->
|
||||||
|
{ok, Terms} = file:consult("jex.eterms");
|
||||||
|
Terms;
|
||||||
|
cfg(safe) ->
|
||||||
|
case file:consult("jex.eterms") of
|
||||||
|
{ok, Terms} -> cfg2(Terms);
|
||||||
|
Error -> Error
|
||||||
|
end.
|
||||||
|
|
||||||
|
cfg2(Cfg) ->
|
||||||
|
% allowed values:
|
||||||
|
% - library
|
||||||
|
% - external
|
||||||
|
% - extension
|
||||||
|
case proplists:get_value(type, Cfg) of
|
||||||
|
% allowed values
|
||||||
|
library -> {ok, Cfg};
|
||||||
|
external -> {ok, Cfg};
|
||||||
|
extension -> {ok, Cfg};
|
||||||
|
% no key
|
||||||
|
undefined -> {error, {no_key, type}};
|
||||||
|
% bad value
|
||||||
|
BadType -> {error, {bad_type, BadType}}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%-----------------------------------------------------------------------------
|
%%-----------------------------------------------------------------------------
|
||||||
%% jex echo
|
%% jex echo
|
||||||
|
|||||||
Reference in New Issue
Block a user