mirror of
https://codeberg.org/streams/streams.git
synced 2024-09-20 02:35:12 +00:00
Merge branch 'dev' into release
This commit is contained in:
commit
1dd3728169
664 changed files with 93609 additions and 55966 deletions
|
@ -1 +1 @@
|
|||
*/10 * * * * cd /app; /usr/local/bin/php Code/Daemon/Run.php Cron > /dev/null 2>&1
|
||||
*/10 * * * * cd /app; /usr/local/bin/php src/Daemon/Run.php Cron > /dev/null 2>&1
|
||||
|
|
1
Code
Symbolic link
1
Code
Symbolic link
|
@ -0,0 +1 @@
|
|||
src
|
2
boot.php
2
boot.php
|
@ -27,7 +27,7 @@ use Code\Lib\Url;
|
|||
*/
|
||||
|
||||
const REPOSITORY_ID = 'streams';
|
||||
const DB_UPDATE_VERSION = 1276;
|
||||
const DB_UPDATE_VERSION = 1278;
|
||||
const PROJECT_BASE = __DIR__;
|
||||
const ACTIVITYPUB_ENABLED = true;
|
||||
const NOMAD_PROTOCOL_VERSION = '13.3';
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-openssl": "*",
|
||||
"sabre/dav": "~3.2",
|
||||
"sabre/dav": "^4.0",
|
||||
"michelf/php-markdown": "^1.7",
|
||||
"bshaffer/oauth2-server-php": "^1.9",
|
||||
"ezyang/htmlpurifier": "^4.9",
|
||||
|
@ -46,14 +46,14 @@
|
|||
"indieweb/rel-me": "^0.1.1",
|
||||
"minishlink/web-push": "^8.0",
|
||||
"stephenhill/base58": "^1.1",
|
||||
"mmccook/php-json-canonicalization-scheme": "^1.0",
|
||||
"phpmailer/phpmailer": "^6.9",
|
||||
"league/oauth2-google": "^4.0",
|
||||
"decomplexity/sendoauth2": "^3.0",
|
||||
"gregwar/captcha": "^1.2",
|
||||
"symfony/symfony": "*",
|
||||
"doctrine/orm": "*",
|
||||
"doctrine/dbal": "*"
|
||||
"doctrine/dbal": "*",
|
||||
"root23/php-json-canonicalization": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "@stable",
|
||||
|
@ -68,7 +68,7 @@
|
|||
"autoload": {
|
||||
"psr-4": {
|
||||
"Include\\": "include/",
|
||||
"Code\\": "Code/"
|
||||
"Code\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
|
@ -82,6 +82,9 @@
|
|||
"php": "8.1"
|
||||
},
|
||||
"notify-on-install": false,
|
||||
"optimize-autoloader": true
|
||||
"optimize-autoloader": true,
|
||||
"allow-plugins": {
|
||||
"symfony/flex": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
391
composer.lock
generated
391
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "09b4e6730c53f30b4f878886a1467f44",
|
||||
"content-hash": "443d65b6df214991d9f4cce01e5c28a3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "beberlei/assert",
|
||||
|
@ -1250,16 +1250,16 @@
|
|||
},
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"version": "2.19.0",
|
||||
"version": "2.19.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/orm.git",
|
||||
"reference": "a809a71aa6a233a6c82e68ebaaf8954adc4998dc"
|
||||
"reference": "b27489348658cd718d18005de37b94f7f8561467"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/a809a71aa6a233a6c82e68ebaaf8954adc4998dc",
|
||||
"reference": "a809a71aa6a233a6c82e68ebaaf8954adc4998dc",
|
||||
"url": "https://api.github.com/repos/doctrine/orm/zipball/b27489348658cd718d18005de37b94f7f8561467",
|
||||
"reference": "b27489348658cd718d18005de37b94f7f8561467",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1345,22 +1345,22 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/orm/issues",
|
||||
"source": "https://github.com/doctrine/orm/tree/2.19.0"
|
||||
"source": "https://github.com/doctrine/orm/tree/2.19.4"
|
||||
},
|
||||
"time": "2024-03-03T17:43:41+00:00"
|
||||
"time": "2024-04-15T13:11:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/persistence",
|
||||
"version": "3.3.1",
|
||||
"version": "3.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/persistence.git",
|
||||
"reference": "b6fd1f126b13c1f7e7321f7338b14a19116b5de4"
|
||||
"reference": "477da35bd0255e032826f440b94b3e37f2d56f42"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/persistence/zipball/b6fd1f126b13c1f7e7321f7338b14a19116b5de4",
|
||||
"reference": "b6fd1f126b13c1f7e7321f7338b14a19116b5de4",
|
||||
"url": "https://api.github.com/repos/doctrine/persistence/zipball/477da35bd0255e032826f440b94b3e37f2d56f42",
|
||||
"reference": "477da35bd0255e032826f440b94b3e37f2d56f42",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1429,7 +1429,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/doctrine/persistence/issues",
|
||||
"source": "https://github.com/doctrine/persistence/tree/3.3.1"
|
||||
"source": "https://github.com/doctrine/persistence/tree/3.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1445,7 +1445,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-01T19:53:13+00:00"
|
||||
"time": "2024-03-12T14:54:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
|
@ -1615,16 +1615,16 @@
|
|||
},
|
||||
{
|
||||
"name": "friendsofphp/proxy-manager-lts",
|
||||
"version": "v1.0.16",
|
||||
"version": "v1.0.18",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/FriendsOfPHP/proxy-manager-lts.git",
|
||||
"reference": "ecadbdc9052e4ad08c60c8a02268712e50427f7c"
|
||||
"reference": "2c8a6cffc3220e99352ad958fe7cf06bf6f7690f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/ecadbdc9052e4ad08c60c8a02268712e50427f7c",
|
||||
"reference": "ecadbdc9052e4ad08c60c8a02268712e50427f7c",
|
||||
"url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/2c8a6cffc3220e99352ad958fe7cf06bf6f7690f",
|
||||
"reference": "2c8a6cffc3220e99352ad958fe7cf06bf6f7690f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1681,7 +1681,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/FriendsOfPHP/proxy-manager-lts/issues",
|
||||
"source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.16"
|
||||
"source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.18"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1693,7 +1693,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-05-24T07:17:17+00:00"
|
||||
"time": "2024-03-20T12:50:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "gregwar/captcha",
|
||||
|
@ -2513,16 +2513,16 @@
|
|||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.8.1",
|
||||
"version": "2.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Masterminds/html5-php.git",
|
||||
"reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf"
|
||||
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf",
|
||||
"reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
|
||||
"reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2530,7 +2530,7 @@
|
|||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8"
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -2574,9 +2574,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.8.1"
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.9.0"
|
||||
},
|
||||
"time": "2023-05-10T11:58:31+00:00"
|
||||
"time": "2024-03-31T07:05:07+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mf2/mf2",
|
||||
|
@ -2760,64 +2760,6 @@
|
|||
},
|
||||
"time": "2023-01-10T17:14:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mmccook/php-json-canonicalization-scheme",
|
||||
"version": "1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mmccook/php-json-canonicalization-scheme.git",
|
||||
"reference": "cd6d3e7645a2c1e62574a9a2437d68e9e74e799f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mmccook/php-json-canonicalization-scheme/zipball/cd6d3e7645a2c1e62574a9a2437d68e9e74e799f",
|
||||
"reference": "cd6d3e7645a2c1e62574a9a2437d68e9e74e799f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.13",
|
||||
"pestphp/pest": "^1.20",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"spatie/ray": "^1.28"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Mmccook\\JsonCanonicalizator\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark M. McCook",
|
||||
"email": "mark.mccook@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "This is my package php-json-canonicalization-scheme",
|
||||
"homepage": "https://github.com/mmccook/php-json-canonicalization-scheme",
|
||||
"keywords": [
|
||||
"mmccook",
|
||||
"php-json-canonicalization-scheme"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/mmccook/php-json-canonicalization-scheme/issues",
|
||||
"source": "https://github.com/mmccook/php-json-canonicalization-scheme/tree/1.0.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/mmccook",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-08-07T18:12:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "p3k/emoji-detector",
|
||||
"version": "0.2.1",
|
||||
|
@ -3483,30 +3425,30 @@
|
|||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "1.1.4",
|
||||
"version": "2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
|
||||
"reference": "ef29f6d262798707a9edd554e2b82517ef3a9376"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/ef29f6d262798707a9edd554e2b82517ef3a9376",
|
||||
"reference": "ef29f6d262798707a9edd554e2b82517ef3a9376",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
"php": ">=8.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1.x-dev"
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "Psr/Log/"
|
||||
"Psr\\Log\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -3527,9 +3469,9 @@
|
|||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/1.1.4"
|
||||
"source": "https://github.com/php-fig/log/tree/2.0.0"
|
||||
},
|
||||
"time": "2021-05-03T11:20:27+00:00"
|
||||
"time": "2021-07-14T16:41:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ralouphie/getallheaders",
|
||||
|
@ -3676,17 +3618,53 @@
|
|||
"time": "2022-12-19T21:55:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/dav",
|
||||
"version": "3.2.3",
|
||||
"name": "root23/php-json-canonicalization",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/dav.git",
|
||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80"
|
||||
"url": "https://github.com/root23/php-json-canonicalization.git",
|
||||
"reference": "be888e03a171c2b9667265d03924bd6bfc3fe85a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/dav/zipball/a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
||||
"reference": "a9780ce4f35560ecbd0af524ad32d9d2c8954b80",
|
||||
"url": "https://api.github.com/repos/root23/php-json-canonicalization/zipball/be888e03a171c2b9667265d03924bd6bfc3fe85a",
|
||||
"reference": "be888e03a171c2b9667265d03924bd6bfc3fe85a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^v3.27.0",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Root23\\JsonCanonicalizer\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"description": "Serialize data into canonical way, based on RFC-8785.",
|
||||
"support": {
|
||||
"issues": "https://github.com/root23/php-json-canonicalization/issues",
|
||||
"source": "https://github.com/root23/php-json-canonicalization/tree/1.0.1"
|
||||
},
|
||||
"time": "2023-09-27T08:27:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/dav",
|
||||
"version": "4.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/dav.git",
|
||||
"reference": "554145304b4a026477d130928d16e626939b0b2a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/dav/zipball/554145304b4a026477d130928d16e626939b0b2a",
|
||||
"reference": "554145304b4a026477d130928d16e626939b0b2a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3694,27 +3672,30 @@
|
|||
"ext-date": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-spl": "*",
|
||||
"lib-libxml": ">=2.7.0",
|
||||
"php": ">=5.5.0",
|
||||
"psr/log": "^1.0",
|
||||
"sabre/event": ">=2.0.0, <4.0.0",
|
||||
"sabre/http": "^4.2.1",
|
||||
"sabre/uri": "^1.0.1",
|
||||
"sabre/vobject": "^4.1.0",
|
||||
"sabre/xml": "^1.4.0"
|
||||
"php": "^7.1.0 || ^8.0",
|
||||
"psr/log": "^1.0 || ^2.0 || ^3.0",
|
||||
"sabre/event": "^5.0",
|
||||
"sabre/http": "^5.0.5",
|
||||
"sabre/uri": "^2.0",
|
||||
"sabre/vobject": "^4.2.1",
|
||||
"sabre/xml": "^2.0.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"evert/phpdoc-md": "~0.1.0",
|
||||
"monolog/monolog": "^1.18",
|
||||
"phpunit/phpunit": "> 4.8, <6.0.0",
|
||||
"sabre/cs": "^1.0.0"
|
||||
"friendsofphp/php-cs-fixer": "^2.19",
|
||||
"monolog/monolog": "^1.27 || ^2.0",
|
||||
"phpstan/phpstan": "^0.12 || ^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": "*",
|
||||
"ext-imap": "*",
|
||||
"ext-pdo": "*"
|
||||
},
|
||||
"bin": [
|
||||
|
@ -3722,17 +3703,9 @@
|
|||
"bin/naturalselection"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sabre\\DAV\\": "lib/DAV/",
|
||||
"Sabre\\CalDAV\\": "lib/CalDAV/",
|
||||
"Sabre\\DAVACL\\": "lib/DAVACL/",
|
||||
"Sabre\\CardDAV\\": "lib/CardDAV/"
|
||||
"Sabre\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -3761,28 +3734,29 @@
|
|||
"issues": "https://github.com/sabre-io/dav/issues",
|
||||
"source": "https://github.com/fruux/sabre-dav"
|
||||
},
|
||||
"time": "2018-10-19T09:58:27+00:00"
|
||||
"time": "2023-12-11T13:01:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/event",
|
||||
"version": "3.0.0",
|
||||
"version": "5.1.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/event.git",
|
||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534"
|
||||
"reference": "d7da22897125d34d7eddf7977758191c06a74497"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/event/zipball/831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||
"reference": "831d586f5a442dceacdcf5e9c4c36a4db99a3534",
|
||||
"url": "https://api.github.com/repos/sabre-io/event/zipball/d7da22897125d34d7eddf7977758191c06a74497",
|
||||
"reference": "d7da22897125d34d7eddf7977758191c06a74497",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5"
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*",
|
||||
"sabre/cs": "~0.0.4"
|
||||
"friendsofphp/php-cs-fixer": "~2.17.1",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -3812,10 +3786,13 @@
|
|||
"keywords": [
|
||||
"EventEmitter",
|
||||
"async",
|
||||
"coroutine",
|
||||
"eventloop",
|
||||
"events",
|
||||
"hooks",
|
||||
"plugin",
|
||||
"promise",
|
||||
"reactor",
|
||||
"signal"
|
||||
],
|
||||
"support": {
|
||||
|
@ -3823,32 +3800,34 @@
|
|||
"issues": "https://github.com/sabre-io/event/issues",
|
||||
"source": "https://github.com/fruux/sabre-event"
|
||||
},
|
||||
"time": "2015-11-05T20:14:39+00:00"
|
||||
"time": "2021-11-04T06:51:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/http",
|
||||
"version": "v4.2.4",
|
||||
"version": "5.1.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/http.git",
|
||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956"
|
||||
"reference": "f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/http/zipball/acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
||||
"reference": "acccec4ba863959b2d10c1fa0fb902736c5c8956",
|
||||
"url": "https://api.github.com/repos/sabre-io/http/zipball/f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02",
|
||||
"reference": "f9f3d1fba8916fa2f4ec25636c4fedc26cb94e02",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-curl": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.4",
|
||||
"sabre/event": ">=1.0.0,<4.0.0",
|
||||
"sabre/uri": "~1.0"
|
||||
"php": "^7.1 || ^8.0",
|
||||
"sabre/event": ">=4.0 <6.0",
|
||||
"sabre/uri": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.3",
|
||||
"sabre/cs": "~0.0.1"
|
||||
"friendsofphp/php-cs-fixer": "~2.17.1",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-curl": " to make http requests with the Client class"
|
||||
|
@ -3884,28 +3863,32 @@
|
|||
"issues": "https://github.com/sabre-io/http/issues",
|
||||
"source": "https://github.com/fruux/sabre-http"
|
||||
},
|
||||
"time": "2018-02-23T11:10:29+00:00"
|
||||
"time": "2023-08-18T01:55:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/uri",
|
||||
"version": "1.2.1",
|
||||
"version": "2.3.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/uri.git",
|
||||
"reference": "ada354d83579565949d80b2e15593c2371225e61"
|
||||
"reference": "7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/ada354d83579565949d80b2e15593c2371225e61",
|
||||
"reference": "ada354d83579565949d80b2e15593c2371225e61",
|
||||
"url": "https://api.github.com/repos/sabre-io/uri/zipball/7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b",
|
||||
"reference": "7e0e7dfd0b7e14346a27eabd66e843a6e7f1812b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.7"
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=4.0,<6.0",
|
||||
"sabre/cs": "~1.0.0"
|
||||
"friendsofphp/php-cs-fixer": "^3.17",
|
||||
"phpstan/extension-installer": "^1.3",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpstan/phpstan-phpunit": "^1.3",
|
||||
"phpstan/phpstan-strict-rules": "^1.5",
|
||||
"phpunit/phpunit": "^9.6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -3940,29 +3923,32 @@
|
|||
"issues": "https://github.com/sabre-io/uri/issues",
|
||||
"source": "https://github.com/fruux/sabre-uri"
|
||||
},
|
||||
"time": "2017-02-20T19:59:28+00:00"
|
||||
"time": "2023-06-09T06:54:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/vobject",
|
||||
"version": "4.2.2",
|
||||
"version": "4.5.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/vobject.git",
|
||||
"reference": "449616b2d45b95c8973975de23f34a3d14f63b4b"
|
||||
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/449616b2d45b95c8973975de23f34a3d14f63b4b",
|
||||
"reference": "449616b2d45b95c8973975de23f34a3d14f63b4b",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
|
||||
"reference": "a6d53a3e5bec85ed3dd78868b7de0f5b4e12f772",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.5",
|
||||
"sabre/xml": ">=1.5 <3.0"
|
||||
"php": "^7.1 || ^8.0",
|
||||
"sabre/xml": "^2.1 || ^3.0 || ^4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "> 4.8.35, <6.0.0"
|
||||
"friendsofphp/php-cs-fixer": "~2.17.1",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/php-invoker": "^2.0 || ^3.1",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
|
||||
},
|
||||
"suggest": {
|
||||
"hoa/bench": "If you would like to run the benchmark scripts"
|
||||
|
@ -4041,20 +4027,20 @@
|
|||
"issues": "https://github.com/sabre-io/vobject/issues",
|
||||
"source": "https://github.com/fruux/sabre-vobject"
|
||||
},
|
||||
"time": "2020-01-14T10:18:45+00:00"
|
||||
"time": "2023-11-09T12:54:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/xml",
|
||||
"version": "1.5.1",
|
||||
"version": "2.2.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/xml.git",
|
||||
"reference": "a367665f1df614c3b8fefc30a54de7cd295e444e"
|
||||
"reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/a367665f1df614c3b8fefc30a54de7cd295e444e",
|
||||
"reference": "a367665f1df614c3b8fefc30a54de7cd295e444e",
|
||||
"url": "https://api.github.com/repos/sabre-io/xml/zipball/9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
|
||||
"reference": "9cde7cdab1e50893cc83b037b40cd47bfde42a2b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4062,12 +4048,13 @@
|
|||
"ext-xmlreader": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"lib-libxml": ">=2.6.20",
|
||||
"php": ">=5.5.5",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"sabre/uri": ">=1.0,<3.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8|~5.7",
|
||||
"sabre/cs": "~1.0.0"
|
||||
"friendsofphp/php-cs-fixer": "~2.17.1",
|
||||
"phpstan/phpstan": "^0.12",
|
||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -4109,7 +4096,7 @@
|
|||
"issues": "https://github.com/sabre-io/xml/issues",
|
||||
"source": "https://github.com/fruux/sabre-xml"
|
||||
},
|
||||
"time": "2019-01-09T13:51:57+00:00"
|
||||
"time": "2023-06-28T12:56:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "simshaun/recurr",
|
||||
|
@ -4171,16 +4158,16 @@
|
|||
},
|
||||
{
|
||||
"name": "smarty/smarty",
|
||||
"version": "v4.4.1",
|
||||
"version": "v4.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/smarty-php/smarty.git",
|
||||
"reference": "f4152e9b814ae2369b6e4935c05e1e0c3654318d"
|
||||
"reference": "732040276609d0c3ad3381781c7444e7c5df9456"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/f4152e9b814ae2369b6e4935c05e1e0c3654318d",
|
||||
"reference": "f4152e9b814ae2369b6e4935c05e1e0c3654318d",
|
||||
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/732040276609d0c3ad3381781c7444e7c5df9456",
|
||||
"reference": "732040276609d0c3ad3381781c7444e7c5df9456",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4231,9 +4218,9 @@
|
|||
"support": {
|
||||
"forum": "https://github.com/smarty-php/smarty/discussions",
|
||||
"issues": "https://github.com/smarty-php/smarty/issues",
|
||||
"source": "https://github.com/smarty-php/smarty/tree/v4.4.1"
|
||||
"source": "https://github.com/smarty-php/smarty/tree/v4.5.2"
|
||||
},
|
||||
"time": "2024-02-26T13:58:37+00:00"
|
||||
"time": "2024-04-05T22:34:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/base64url",
|
||||
|
@ -4377,16 +4364,16 @@
|
|||
},
|
||||
{
|
||||
"name": "spomky-labs/pki-framework",
|
||||
"version": "1.1.1",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Spomky-Labs/pki-framework.git",
|
||||
"reference": "86102bdd19379b2c6e5b0feb94fd490d40e7d133"
|
||||
"reference": "0b10c8b53366729417d6226ae89a665f9e2d61b6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/86102bdd19379b2c6e5b0feb94fd490d40e7d133",
|
||||
"reference": "86102bdd19379b2c6e5b0feb94fd490d40e7d133",
|
||||
"url": "https://api.github.com/repos/Spomky-Labs/pki-framework/zipball/0b10c8b53366729417d6226ae89a665f9e2d61b6",
|
||||
"reference": "0b10c8b53366729417d6226ae89a665f9e2d61b6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -4398,7 +4385,7 @@
|
|||
"ekino/phpstan-banned-code": "^1.0",
|
||||
"ext-gmp": "*",
|
||||
"ext-openssl": "*",
|
||||
"infection/infection": "^0.27",
|
||||
"infection/infection": "^0.28",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpstan/extension-installer": "^1.3",
|
||||
"phpstan/phpstan": "^1.8",
|
||||
|
@ -4406,8 +4393,8 @@
|
|||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.1",
|
||||
"phpstan/phpstan-strict-rules": "^1.3",
|
||||
"phpunit/phpunit": "^10.1",
|
||||
"rector/rector": "^0.19",
|
||||
"phpunit/phpunit": "^10.1|^11.0",
|
||||
"rector/rector": "^1.0",
|
||||
"roave/security-advisories": "dev-latest",
|
||||
"symfony/phpunit-bridge": "^6.4|^7.0",
|
||||
"symfony/string": "^6.4|^7.0",
|
||||
|
@ -4472,7 +4459,7 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Spomky-Labs/pki-framework/issues",
|
||||
"source": "https://github.com/Spomky-Labs/pki-framework/tree/1.1.1"
|
||||
"source": "https://github.com/Spomky-Labs/pki-framework/tree/1.2.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4484,7 +4471,7 @@
|
|||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2024-02-05T20:37:46+00:00"
|
||||
"time": "2024-03-30T18:03:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "stephenhill/base58",
|
||||
|
@ -8037,16 +8024,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "10.1.13",
|
||||
"version": "10.1.14",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "d51c3aec14896d5e80b354fad58e998d1980f8f8"
|
||||
"reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d51c3aec14896d5e80b354fad58e998d1980f8f8",
|
||||
"reference": "d51c3aec14896d5e80b354fad58e998d1980f8f8",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
|
||||
"reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -8103,7 +8090,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.13"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -8111,7 +8098,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-09T16:54:15+00:00"
|
||||
"time": "2024-03-12T15:33:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -8358,16 +8345,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.5.12",
|
||||
"version": "10.5.18",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "41a9886b85ac7bf3929853baf96b95361cd69d2b"
|
||||
"reference": "835df1709ac6c968ba34bf23f3c30e5d5a266de8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/41a9886b85ac7bf3929853baf96b95361cd69d2b",
|
||||
"reference": "41a9886b85ac7bf3929853baf96b95361cd69d2b",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/835df1709ac6c968ba34bf23f3c30e5d5a266de8",
|
||||
"reference": "835df1709ac6c968ba34bf23f3c30e5d5a266de8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -8439,7 +8426,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.12"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.18"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -8455,20 +8442,20 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-03-09T12:04:07+00:00"
|
||||
"time": "2024-04-14T07:05:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psy/psysh",
|
||||
"version": "v0.12.0",
|
||||
"version": "v0.12.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/psysh.git",
|
||||
"reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d"
|
||||
"reference": "b6b6cce7d3ee8fbf31843edce5e8f5a72eff4a73"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/750bf031a48fd07c673dbe3f11f72362ea306d0d",
|
||||
"reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d",
|
||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/b6b6cce7d3ee8fbf31843edce5e8f5a72eff4a73",
|
||||
"reference": "b6b6cce7d3ee8fbf31843edce5e8f5a72eff4a73",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -8532,9 +8519,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/bobthecow/psysh/issues",
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.0"
|
||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.3"
|
||||
},
|
||||
"time": "2023-12-20T15:28:09+00:00"
|
||||
"time": "2024-04-02T15:57:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -8908,16 +8895,16 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "6.0.1",
|
||||
"version": "6.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951"
|
||||
"reference": "8074dbcd93529b357029f5cc5058fd3e43666984"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/43c751b41d74f96cbbd4e07b7aec9675651e2951",
|
||||
"reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984",
|
||||
"reference": "8074dbcd93529b357029f5cc5058fd3e43666984",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -8932,7 +8919,7 @@
|
|||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "6.0-dev"
|
||||
"dev-main": "6.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -8960,7 +8947,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/environment/issues",
|
||||
"security": "https://github.com/sebastianbergmann/environment/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/6.0.1"
|
||||
"source": "https://github.com/sebastianbergmann/environment/tree/6.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -8968,7 +8955,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-04-11T05:39:26+00:00"
|
||||
"time": "2024-03-23T08:47:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
|
|
|
@ -304,9 +304,9 @@ function configure_daily_update {
|
|||
function configure_cron_daily {
|
||||
print_info "configuring cron..."
|
||||
# every 10 min for Run.php
|
||||
if [[ -z $(grep "/var/www/$install_folder; php Code/Daemon/Run.php" /etc/crontab) ]]
|
||||
if [[ -z $(grep "/var/www/$install_folder; php src/Daemon/Run.php" /etc/crontab) ]]
|
||||
then
|
||||
echo "*/10 * * * * www-data cd $install_path; php Code/Daemon/Run.php Cron >> /dev/null 2>&1" >> /etc/crontab
|
||||
echo "*/10 * * * * www-data cd $install_path; php src/Daemon/Run.php Cron >> /dev/null 2>&1" >> /etc/crontab
|
||||
fi
|
||||
|
||||
# Run external script daily at 05:30 to update repository core and addon
|
||||
|
|
|
@ -518,9 +518,9 @@ function configure_daily_update {
|
|||
function configure_cron_daily {
|
||||
print_info "configuring cron..."
|
||||
# every 10 min for poller.php
|
||||
if [ -z "`grep 'php Code/Daemon/Run.php' /etc/crontab`" ]
|
||||
if [ -z "`grep 'php src/Daemon/Run.php' /etc/crontab`" ]
|
||||
then
|
||||
echo "*/10 * * * * www-data cd $install_path; php Code/Daemon/Run.php Cron >> /dev/null 2>&1" >> /etc/crontab
|
||||
echo "*/10 * * * * www-data cd $install_path; php src/Daemon/Run.php Cron >> /dev/null 2>&1" >> /etc/crontab
|
||||
fi
|
||||
# Run external script daily at 05:30
|
||||
# - stop apache/nginx and mysql-server
|
||||
|
|
|
@ -14,12 +14,7 @@ Note, in many cases this must be the same as the authenticated user email config
|
|||
|
||||
![Streams site settings](/doc/admin/en/images/site-settings.webp "Streams site settings")
|
||||
|
||||
## Step 2: Enable PHPMAILER
|
||||
Navigate to the Streams root folder on the command line. Then enable the PHPMAILER plugin using this command:
|
||||
```
|
||||
./util/addons install phpmailer
|
||||
```
|
||||
## Step 3: Configure PHPMAILER
|
||||
## Step 2: Configure PHPMAILER
|
||||
The configuration depends on the SMTP service you are using. Here is a basic example:
|
||||
|
||||
<pre>// PHPMailer addon
|
||||
|
|
|
@ -21,16 +21,17 @@ In the conversational model, the same basic steps occur, but respects the rights
|
|||
|
||||
A constrained conversation is implemented as a Collection. [FEP-400e](https://codeberg.org/fediverse/fep/src/branch/main/fep/400e/fep-400e.md) provides a model for working with collections. In that proposal, ActivityPub objects which are created as part of a collection are indicated by a `target` "stub" property containing
|
||||
|
||||
- type -- ( `Collection` or `OrderedCollection` )
|
||||
- type -- ( `Collection` or `OrderedCollection` of activities)
|
||||
- id -- a URL where this collection can be found
|
||||
- attributedTo -- the `id` of the collection owner
|
||||
|
||||
In a constrained conversation, conforming implementations will implement FEP-400e with some very minor additions:
|
||||
In a constrained conversation, conforming implementations will implement FEP-400e with some very minor additions:
|
||||
- The collection contains complete activities, not simple objects.
|
||||
- In a constrained conversation, the target->id and the context are identical. This provides easy identification.
|
||||
- In a constrained conversation, replies SHOULD only be addressed to the target->attributedTo actor.
|
||||
- When receiving a correctly signed `Add` activity, checking that the id of the target is a collection owned by `actor` is slightly different from FEP-400e. This can be accomplished by fetching the Collection object and validating the attributedTo field.
|
||||
|
||||
Processing is otherwise identical. In the reference implementation of conversation containers by the streams repository, signed objects are often transmitted instead of just transmitting the ids, and these are signed using a combination of [FEP-521a](https://codeberg.org/fediverse/fep/src/branch/main/fep/c390/fep-521a.md) and [FEP-8b32](https://codeberg.org/fediverse/fep/src/branch/main/fep/8b32/fep-8b32.md).
|
||||
Processing is otherwise identical. In the reference implementation of conversation containers by the streams repository, signed objects are often transmitted instead of just transmitting the ids, and these are signed using a combination of [FEP-521a](https://codeberg.org/fediverse/fep/src/branch/main/fep/521a/fep-521a.md) and [FEP-8b32](https://codeberg.org/fediverse/fep/src/branch/main/fep/8b32/fep-8b32.md).
|
||||
|
||||
### Example activities
|
||||
|
||||
|
@ -205,7 +206,7 @@ Processing is otherwise identical. In the reference implementation of conversati
|
|||
}
|
||||
},
|
||||
"target": {
|
||||
"id": "https://streams.lndo.site/item/ed4775f8-18ee-46a5-821e-b2ed2dc546e8",
|
||||
"id": "https://streams.lndo.site/conversation/ed4775f8-18ee-46a5-821e-b2ed2dc546e8",
|
||||
"type": "Collection",
|
||||
"attributedTo": "https://streams.lndo.site/channel/red"
|
||||
},
|
||||
|
@ -442,7 +443,7 @@ Processing is otherwise identical. In the reference implementation of conversati
|
|||
}
|
||||
},
|
||||
"target": {
|
||||
"id": "https://streams.lndo.site/item/ed4775f8-18ee-46a5-821e-b2ed2dc546e8",
|
||||
"id": "https://streams.lndo.site/conversation/ed4775f8-18ee-46a5-821e-b2ed2dc546e8",
|
||||
"type": "Collection",
|
||||
"attributedTo": "https://streams.lndo.site/channel/red"
|
||||
},
|
||||
|
|
|
@ -34,7 +34,7 @@ Then we're going to create a comment block to describe the addon. There's a spec
|
|||
[/code]
|
||||
These tags will be seen by the site administrator when he/she installs or manages plugins from the admin panel. There can be more than one author. Just add another line starting with 'Author:'.
|
||||
|
||||
Next we will create a 'use' statement to include the code in Code/Lib/Apps.php
|
||||
Next we will create a 'use' statement to include the code in src/Lib/Apps.php
|
||||
|
||||
[code]
|
||||
use Code\Lib\Apps;
|
||||
|
|
|
@ -115,13 +115,13 @@ Ze względu na bezpieczeństwo witryny nie ma możliwości zapewnienia dostępu
|
|||
|
||||
Skonfiguruj zadanie crona lub zaplanowane zadanie, aby uruchamiać menedżera crona co 10-15 minut do wykonywania w tle zadań przetwarzania i konserwacji. Przykład:
|
||||
|
||||
cd /base/directory; /path/to/php Code/Daemon/Run.php Cron
|
||||
cd /base/directory; /path/to/php src/Daemon/Run.php Cron
|
||||
|
||||
Zmień "/base/directory" i "/path/to/php" na swoje rzeczywiste ścieżki.
|
||||
|
||||
Jeśli używasz serwera Linux, uruchom "crontab -e" i dodaj linię podobną do pokazanej niżej, zastępując ścieżki i ustawienia swoimi danymi:
|
||||
|
||||
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php Code/Daemon/Run.php Cron > /dev/null 2>&1
|
||||
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php src/Daemon/Run.php Cron > /dev/null 2>&1
|
||||
|
||||
Na ogół możesz znaleźć lokalizację PHP, wykonując "which php". Jeśli masz problemy z tą sekcją, skontaktuj się z dostawcą usług hostingowych w celu uzyskania pomocy. Oprogramowanie nie będzie działać poprawnie, jeśli nie możesz wykonać tego kroku.
|
||||
|
||||
|
|
|
@ -274,46 +274,54 @@ function bb_parse_crypt($match)
|
|||
{
|
||||
|
||||
$matches = [];
|
||||
$attributes = $match[1];
|
||||
$hint = '';
|
||||
$algorithm = '';
|
||||
$payload = $match[1];
|
||||
|
||||
$algorithm = "";
|
||||
if (isset($match[2])) {
|
||||
// backwards compatibility
|
||||
|
||||
preg_match("/alg='(.*?)'/ism", $attributes, $matches);
|
||||
if ($matches[1] != "") {
|
||||
$algorithm = $matches[1];
|
||||
$attributes = $match[1];
|
||||
$payload = $match[2];
|
||||
|
||||
preg_match("/alg='(.*?)'/ism", $attributes, $matches);
|
||||
$algorithm = $matches[1] ?? '';
|
||||
|
||||
if (!$algorithm) {
|
||||
preg_match("/alg=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
||||
$algorithm = $matches[1] ?? '';
|
||||
}
|
||||
|
||||
if (!$algorithm) {
|
||||
preg_match("/alg=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
||||
$algorithm = $matches[1] ?? '';
|
||||
}
|
||||
|
||||
$matches = [];
|
||||
|
||||
preg_match("/hint='(.*?)'/ism", $attributes, $matches);
|
||||
$hint = $matches[1] ?? '';
|
||||
|
||||
if (!$hint) {
|
||||
preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
||||
$hint = $matches[1] ?? '';
|
||||
}
|
||||
|
||||
if (!$hint) {
|
||||
preg_match("/hint=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
||||
$hint = $matches[1] ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
preg_match("/alg=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
||||
if ($matches[1] != "") {
|
||||
$algorithm = $matches[1];
|
||||
$x = random_string(32);
|
||||
|
||||
$onclick = 'onclick="sodium_decrypt(\'' . $payload . '\',\'#' . $x . '\');"';
|
||||
|
||||
if (in_array($algorithm, ['AES-128-CCM', 'rot13', 'triple-rot13'])) {
|
||||
// backwards compatibility
|
||||
$onclick = 'onclick="hz_decrypt(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $payload . '\',\'#' . $x . '\');"';
|
||||
}
|
||||
|
||||
preg_match("/alg=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
||||
if ($matches[1] != "") {
|
||||
$algorithm = $matches[1];
|
||||
}
|
||||
|
||||
$hint = "";
|
||||
$matches = [];
|
||||
|
||||
preg_match("/hint='(.*?)'/ism", $attributes, $matches);
|
||||
if ($matches[1] != "") {
|
||||
$hint = $matches[1];
|
||||
}
|
||||
preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches);
|
||||
if ($matches[1] != "") {
|
||||
$hint = $matches[1];
|
||||
}
|
||||
preg_match("/hint=\\\"(.*?)\\\"/ism", $attributes, $matches);
|
||||
if ($matches[1] != "") {
|
||||
$hint = $matches[1];
|
||||
}
|
||||
|
||||
$x = random_string();
|
||||
|
||||
$f = 'hz_decrypt';
|
||||
|
||||
$onclick = 'onclick="' . $f . '(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');"';
|
||||
$label = t('Encrypted content');
|
||||
|
||||
$Text = '<br><div id="' . $x . '"><img class="cursor-pointer" src="' . z_root() . '/images/lock_icon.svg" ' . $onclick . ' alt="' . $label . '" title="' . $label . '" /></div><br><br>' . bb_parse_b64_crypt($match);
|
||||
|
@ -329,14 +337,9 @@ function bb_parse_crypt($match)
|
|||
*/
|
||||
function bb_parse_b64_crypt($match)
|
||||
{
|
||||
|
||||
if (empty($match[2])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = '----- ENCRYPTED CONTENT -----' . "\n";
|
||||
$r .= base64_encode($match[1]) . "." . $match[2] . "\n";
|
||||
$r .= '----- END ENCRYPTED CONTENT -----' . "\n";
|
||||
$r = '-----BEGIN ENCRYPTED MESSAGE-----' . "\n";
|
||||
$r .= base64_encode($match[1]) . (($match[2]) ? "." . $match[2] : '') . "\n";
|
||||
$r .= '-----END ENCRYPTED MESSAGE-----' . "\n";
|
||||
|
||||
$r = '<code>' . str_replace("\n", '<br>', wordwrap($r, 75, "\n", true)) . '</code>';
|
||||
|
||||
|
@ -1760,6 +1763,8 @@ function bbcode($Text, $options = [])
|
|||
if (str_contains($Text, '[/url]')) {
|
||||
$Text = preg_replace("/\#\^\[url\]([$URLSearchString]*?)\[\/url\]/ism", '<a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
|
||||
$Text = preg_replace("/\#\^\[url\=([$URLSearchString]*?)\](.*?)\[\/url\]/ism", '<a class="bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
|
||||
$Text = preg_replace("/\#\[url\]([$URLSearchString]*?)\[\/url\]/ism", '#<a class="hashtag" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
|
||||
$Text = preg_replace("/\#\[url\=([$URLSearchString]*?)\](.*?)\[\/url\]/ism", '#<a class="hashtag" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
|
||||
$Text = preg_replace("/\[url\]([$URLSearchString]*?)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
|
||||
$Text = preg_replace("/\@(\!?)\[url\=([$URLSearchString]*?)\](.*?)\[\/url\]/ism", '@$1<span class="h-card"><a class="u-url mention" href="$2" ' . $target . ' rel="nofollow noopener" >$3</a></span>', $Text);
|
||||
$Text = preg_replace("/\[url\=([$URLSearchString]*?)\](.*?)\[\/url\]/ism", '<a href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
|
||||
|
@ -1769,6 +1774,8 @@ function bbcode($Text, $options = [])
|
|||
// render hubzilla bookmarks as normal links
|
||||
$Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*?)\[\/zrl\]/ism", '<a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
|
||||
$Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*?)\](.*?)\[\/zrl\]/ism", '<a class="zrl bookmark" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
|
||||
$Text = preg_replace("/\#\[zrl\]([$URLSearchString]*?)\[\/zrl\]/ism", '#<a class="zrl hashtag" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
|
||||
$Text = preg_replace("/\#\[zrl\=([$URLSearchString]*?)\](.*?)\[\/zrl\]/ism", '#<a class="zrl hashtag" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
|
||||
$Text = preg_replace("/\[zrl\]([$URLSearchString]*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$1</a>', $Text);
|
||||
$Text = preg_replace("/\@(\!?)\[zrl\=([$URLSearchString]*?)\](.*?)\[\/zrl\]/ism", '@$1<span class="h-card"><a class="zrl u-url mention" href="$2" ' . $target . ' rel="nofollow noopener" >$3</a></span>', $Text);
|
||||
$Text = preg_replace("/\[zrl\=([$URLSearchString]*?)\](.*?)\[\/zrl\]/ism", '<a class="zrl" href="$1" ' . $target . ' rel="nofollow noopener" >$2</a>', $Text);
|
||||
|
@ -2098,6 +2105,7 @@ function bbcode($Text, $options = [])
|
|||
if ($activitypub) {
|
||||
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_b64_crypt', $Text);
|
||||
} else {
|
||||
$Text = preg_replace_callback("/\[crypt\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
|
||||
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -303,7 +303,7 @@ function mark_orphan_hubsxchans()
|
|||
|
||||
|
||||
$r = q("update hubloc set hubloc_deleted = 1 where hubloc_deleted = 0
|
||||
and hubloc_network in ('nomad','zot6') and hubloc_connected != '0001-01-01 00:00:00' hubloc_connected < %s - interval %s",
|
||||
and hubloc_network in ('nomad','zot6') and hubloc_connected != '0001-01-01 00:00:00' and hubloc_connected < %s - interval %s",
|
||||
db_utcnow(), db_quoteinterval('36 day')
|
||||
);
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ define ( 'TERM_THING', 7 );
|
|||
define ( 'TERM_BOOKMARK', 8 );
|
||||
define ( 'TERM_HIERARCHY', 9 );
|
||||
define ( 'TERM_COMMUNITYTAG', 10 );
|
||||
define ( 'TERM_FORUM', 11 );
|
||||
define ( 'TERM_GROUP', 11 );
|
||||
define ( 'TERM_EMOJI', 12 );
|
||||
define ( 'TERM_QUOTED', 13 );
|
||||
|
||||
|
|
|
@ -263,7 +263,7 @@ function count_descendants($item)
|
|||
*/
|
||||
function visible_activity($item)
|
||||
{
|
||||
$hidden_activities = [ ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Undo', 'Accept', 'Reject' ];
|
||||
$hidden_activities = [ ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Announce', 'Undo', 'Accept', 'Reject' ];
|
||||
|
||||
if (intval($item['item_notshown'])) {
|
||||
return false;
|
||||
|
@ -438,6 +438,7 @@ function conversation($items, $mode, $update, $page_mode = 'traditional', $prepa
|
|||
$conv_responses = [
|
||||
'like' => [ 'title' => t('Likes', 'title') ],
|
||||
'dislike' => [ 'title' => t('Dislikes', 'title') ],
|
||||
'repeat' => [ 'title' => t('Repeats', 'title') ],
|
||||
'attendyes' => [ 'title' => t('Attending', 'title') ],
|
||||
'attendno' => [ 'title' => t('Not attending', 'title') ],
|
||||
'attendmaybe' => [ 'title' => t('Might attend', 'title') ]
|
||||
|
@ -944,6 +945,9 @@ function builtin_activity_puller($item, &$conv_responses)
|
|||
case 'dislike':
|
||||
$verb = ACTIVITY_DISLIKE;
|
||||
break;
|
||||
case 'repeat':
|
||||
$verb = 'Announce';
|
||||
break;
|
||||
case 'attendyes':
|
||||
$verb = 'Accept';
|
||||
break;
|
||||
|
@ -989,6 +993,7 @@ function builtin_activity_puller($item, &$conv_responses)
|
|||
$conv_responses[$mode][$item['thr_parent'] . '-l'][] = $url;
|
||||
if (get_observer_hash() && get_observer_hash() === $item['author_xchan']) {
|
||||
$conv_responses[$mode][$item['thr_parent'] . '-m'] = true;
|
||||
$conv_responses[$mode][$item['thr_parent'] . '-mitem'] = $item['id'];
|
||||
}
|
||||
|
||||
// there can only be one activity verb per item so if we found anything, we can stop looking
|
||||
|
@ -1893,6 +1898,12 @@ function get_response_button_text($v, $count)
|
|||
} else {
|
||||
return t('Dislikes', 'noun');
|
||||
}
|
||||
case 'repeat':
|
||||
if (get_config('system', 'show_like_counts', true)) {
|
||||
return $count . ' ' . tt('Repeat', 'Repeats', $count, 'noun');
|
||||
} else {
|
||||
return t('Repeats', 'noun');
|
||||
}
|
||||
case 'attendyes':
|
||||
return $count . ' ' . tt('Attending', 'Attending', $count, 'noun');
|
||||
case 'attendno':
|
||||
|
|
|
@ -37,7 +37,7 @@ function get_public_feed($channel, $params)
|
|||
$params['top'] = ((x($params, 'top')) ? intval($params['top']) : 0);
|
||||
$params['cat'] = ((x($params, 'cat')) ? $params['cat'] : '');
|
||||
$params['compat'] = ((x($params, 'compat')) ? intval($params['compat']) : 0);
|
||||
|
||||
$params['noadd'] = ((x($params, 'noadd')) ? intval($params['noadd']) : 1);
|
||||
|
||||
switch ($params['type']) {
|
||||
case 'json':
|
||||
|
@ -147,7 +147,8 @@ function get_feed_for($channel, $observer_hash, $params)
|
|||
'order' => dbesc('post'),
|
||||
'top' => $params['top'],
|
||||
'cat' => $params['cat'],
|
||||
'compat' => $params['compat']
|
||||
'compat' => $params['compat'],
|
||||
'noadd' => $params['noadd']
|
||||
],
|
||||
$channel,
|
||||
$observer_hash,
|
||||
|
|
|
@ -248,6 +248,8 @@ function html2bbcode($message)
|
|||
|
||||
node2bbcode($doc, 'a', array('href' => '/(.+)/'), '[url=$1]', '[/url]');
|
||||
|
||||
node2bbcode($doc, 'img', array('src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/', 'alt' => '/(.+)/'), '[img width=\'$2\' height=\'$3\' src=\'$1\' alt=\'$4\']', '[/img]');
|
||||
node2bbcode($doc, 'img', array('src' => '/(.+)/', 'alt' => '/(.+)/'), '[img src=\'$1\' alt=\'$2\']', '[/img]');
|
||||
node2bbcode($doc, 'img', array('src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'), '[img=$2x$3]$1', '[/img]');
|
||||
node2bbcode($doc, 'img', array('src' => '/(.+)/'), '[img]$1', '[/img]');
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
|
||||
use Code\Lib\Channel;
|
||||
use Code\Lib\Config;
|
||||
use Code\Lib\Libzot;
|
||||
use Code\Lib\Time;
|
||||
use Code\Lib\Url;
|
||||
use Code\Daemon\Run;
|
||||
|
@ -74,12 +76,17 @@ function site_store_lowlevel($arr)
|
|||
return create_table_from_array('site', $store);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes foreign location records which are no longer valid
|
||||
* @return void
|
||||
*/
|
||||
function prune_hub_reinstalls()
|
||||
{
|
||||
|
||||
$r = q(
|
||||
"select site_url from site where site_type = %d",
|
||||
intval(SITE_TYPE_ZOT)
|
||||
"select site_url from site where site_type = %d && site_url != '%s'",
|
||||
intval(SITE_TYPE_ZOT),
|
||||
dbesc(z_root())
|
||||
);
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
|
@ -99,10 +106,7 @@ function prune_hub_reinstalls()
|
|||
|
||||
if (($d1 < $d2) && ($x[0]['hubloc_sitekey'])) {
|
||||
logger('prune_hub_reinstalls: removing dead hublocs at ' . $rr['site_url']);
|
||||
$y = q(
|
||||
"delete from hubloc where hubloc_sitekey = '%s'",
|
||||
dbesc($x[0]['hubloc_sitekey'])
|
||||
);
|
||||
hubloc_delete($x[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,72 +115,96 @@ function prune_hub_reinstalls()
|
|||
|
||||
|
||||
/**
|
||||
* @brief Remove obsolete hublocs.
|
||||
* @brief checks and repairs local hubloc records
|
||||
*
|
||||
* Get rid of any hublocs which are ours but aren't valid anymore -
|
||||
* e.g. they point to a different and perhaps transient URL that we aren't using.
|
||||
*
|
||||
* I need to stress that this shouldn't happen. fix_system_urls() fixes hublocs
|
||||
* when it discovers the URL has changed. So it's unclear how we could end up
|
||||
* with URLs pointing to the old site name. But it happens. This may be an artifact
|
||||
* of an old bug or maybe a regression in some newer code. In any event, they
|
||||
* mess up communications and we have to take action if we find any.
|
||||
* This shouldn't happen. But it does.
|
||||
*/
|
||||
function remove_obsolete_hublocs()
|
||||
function check_hublocs()
|
||||
{
|
||||
|
||||
logger('remove_obsolete_hublocs', LOGGER_DEBUG);
|
||||
$sitekey = Config::Get('system', 'pubkey');
|
||||
$interval = Config::Get('system', 'delivery_interval', 2);
|
||||
|
||||
// First make sure we have any hublocs (at all) with this URL and sitekey.
|
||||
// We don't want to perform this operation while somebody is in the process
|
||||
// of renaming their hub or installing certs.
|
||||
|
||||
$r = q(
|
||||
"select hubloc_id from hubloc where hubloc_url = '%s' and hubloc_sitekey = '%s'",
|
||||
dbesc(z_root()),
|
||||
dbesc(get_config('system', 'pubkey'))
|
||||
);
|
||||
if ((! $r) || (! count($r))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Good. We have at least one *valid* hubloc.
|
||||
|
||||
// Do we have any invalid ones?
|
||||
|
||||
$r = q(
|
||||
$wrong_urls = q(
|
||||
"select hubloc_id from hubloc where hubloc_sitekey = '%s' and hubloc_url != '%s'",
|
||||
dbesc(get_config('system', 'pubkey')),
|
||||
dbesc($sitekey),
|
||||
dbesc(z_root())
|
||||
);
|
||||
$p = q(
|
||||
$wrong_keys = q(
|
||||
"select hubloc_id from hubloc where hubloc_sitekey != '%s' and hubloc_url = '%s'",
|
||||
dbesc(get_config('system', 'pubkey')),
|
||||
dbesc($sitekey),
|
||||
dbesc(z_root())
|
||||
);
|
||||
if (is_array($r) && is_array($p)) {
|
||||
$r = array_merge($r, $p);
|
||||
if (is_array($wrong_urls) && is_array($wrong_keys)) {
|
||||
$invalids = array_merge($wrong_urls, $wrong_keys);
|
||||
}
|
||||
|
||||
if (! $r) {
|
||||
return;
|
||||
if ($invalids) {
|
||||
foreach ($invalids as $hubloc) {
|
||||
logger('Removing invalid hubloc for ' . $hubloc['hubloc_addr'], LOGGER_DEBUG);
|
||||
hubloc_delete($hubloc);
|
||||
$channel = Channel::from_hash($hubloc['hubloc_hash']);
|
||||
if ($channel) {
|
||||
Run::Summon(['Notifier', 'refresh_all', $channel['channel_id']]);
|
||||
if ($interval) {
|
||||
@time_sleep_until(microtime(true) + (float)$interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We've got invalid hublocs. Get rid of them.
|
||||
$channels = q("select * from channel where channel_removed = 0");
|
||||
|
||||
logger('remove_obsolete_hublocs: removing ' . count($r) . ' hublocs.');
|
||||
|
||||
$interval = ((get_config('system', 'delivery_interval') !== false)
|
||||
? intval(get_config('system', 'delivery_interval')) : 2 );
|
||||
|
||||
// mark the hublocs deleted; spread out the notifications
|
||||
foreach ($r as $rr) {
|
||||
hubloc_delete($rr);
|
||||
$x = Channel::from_hash($rr['hubloc_hash']);
|
||||
if ($x) {
|
||||
Run::Summon([ 'Notifier', 'refresh_all', $x['channel_id'] ]);
|
||||
if ($interval) {
|
||||
@time_sleep_until(microtime(true) + (float) $interval);
|
||||
if ($channels) {
|
||||
foreach ($channels as $channel) {
|
||||
$hubs = q("select * from hubloc where hubloc_hash = '%s' and
|
||||
hubloc_url = '%s' and hubloc_sitekey = '%s'",
|
||||
dbesc($channel['channel_hash']),
|
||||
dbesc(z_root()),
|
||||
dbesc($sitekey)
|
||||
);
|
||||
if (!$hubs) {
|
||||
logger('Repairing hubloc for ' . $channel['channel_address'], LOGGER_DEBUG);
|
||||
// This channel does not have a valid location (hubloc)
|
||||
// set for this site.
|
||||
$hubloc_addr = Channel::get_webfinger($channel);
|
||||
$primary = 1; // if xchan is missing, make this location the primary
|
||||
$xchans = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($channel['channel_hash'])
|
||||
);
|
||||
if ($xchans) {
|
||||
$primary = (int)$xchans[0]['xchan_addr'] === $hubloc_addr;
|
||||
}
|
||||
$result = hubloc_store_lowlevel(
|
||||
[
|
||||
'hubloc_guid' => $channel['channel_guid'],
|
||||
'hubloc_guid_sig' => $channel['channel_guid_sig'],
|
||||
'hubloc_hash' => $channel['channel_hash'],
|
||||
'hubloc_id_url' => Channel::url($channel),
|
||||
'hubloc_addr' => Channel::get_webfinger($channel),
|
||||
'hubloc_primary' => $primary,
|
||||
'hubloc_url' => z_root(),
|
||||
'hubloc_url_sig' => Libzot::sign(z_root(), $channel['channel_prvkey']),
|
||||
'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), $sitekey),
|
||||
'hubloc_host' => App::get_hostname(),
|
||||
'hubloc_callback' => z_root() . '/nomad',
|
||||
'hubloc_sitekey' => $sitekey,
|
||||
'hubloc_network' => 'nomad',
|
||||
'hubloc_updated' => Time::convert(),
|
||||
'hubloc_connected' => Time::convert()
|
||||
]
|
||||
);
|
||||
if ($result) {
|
||||
q("delete from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' and hubloc_sitekey != '%s'",
|
||||
dbesc($channel['channel_hash']),
|
||||
dbesc(z_root()),
|
||||
dbesc($sitekey)
|
||||
);
|
||||
Run::Summon([ 'Notifier', 'refresh_all', $channel['channel_id'] ]);
|
||||
if ($interval) {
|
||||
@time_sleep_until(microtime(true) + (float) $interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -324,6 +324,10 @@ function can_comment_on_post($observer_xchan, $item)
|
|||
if (intval($item['item_wall']) && perm_is_allowed($item['uid'], $observer_xchan, 'post_comments')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($item['owner']['xchan_network']) && $item['owner']['xchan_network'] === 'activitypub') {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'self':
|
||||
default:
|
||||
|
@ -1100,7 +1104,7 @@ function encode_item_xchan($xchan) {
|
|||
function encode_item_terms($terms,$mirror = false) {
|
||||
$ret = [];
|
||||
|
||||
$allowed_export_terms = [TERM_UNKNOWN, TERM_HASHTAG, TERM_MENTION, TERM_CATEGORY, TERM_BOOKMARK, TERM_COMMUNITYTAG, TERM_FORUM];
|
||||
$allowed_export_terms = [TERM_UNKNOWN, TERM_HASHTAG, TERM_MENTION, TERM_CATEGORY, TERM_BOOKMARK, TERM_COMMUNITYTAG, TERM_GROUP];
|
||||
|
||||
if($mirror) {
|
||||
$allowed_export_terms[] = TERM_PCATEGORY;
|
||||
|
@ -1199,7 +1203,7 @@ function decode_tags($t) {
|
|||
$tag['ttype'] = TERM_COMMUNITYTAG;
|
||||
break;
|
||||
case 'forum':
|
||||
$tag['ttype'] = TERM_FORUM;
|
||||
$tag['ttype'] = TERM_GROUP;
|
||||
break;
|
||||
default:
|
||||
case 'unknown':
|
||||
|
@ -1940,7 +1944,8 @@ function addToCollectionAndSync($ret)
|
|||
$channel = Channel::from_id($ret['item']['uid']);
|
||||
if ($channel && $channel['channel_hash'] === $ret['item']['owner_xchan']) {
|
||||
$items = [$ret['item']];
|
||||
if ((int)$items[0]['item_blocked'] === ITEM_MODERATED) {
|
||||
if ((int)$items[0]['item_blocked'] === ITEM_MODERATED
|
||||
|| (int)$items[0]['item_unpublished'] || (int)$items[0]['item_delayed']) {
|
||||
return $ret;
|
||||
}
|
||||
xchan_query($items);
|
||||
|
@ -2674,7 +2679,7 @@ function tag_deliver($uid, $item_id) {
|
|||
*/
|
||||
|
||||
|
||||
$terms = ((isset($item['term'])) ? get_terms_oftype($item['term'],[TERM_MENTION, TERM_FORUM]) : false);
|
||||
$terms = ((isset($item['term'])) ? get_terms_oftype($item['term'],[TERM_MENTION, TERM_GROUP]) : false);
|
||||
|
||||
$pterms = ((isset($item['term'])) ? get_terms_oftype($item['term'], [TERM_PCATEGORY, TERM_HASHTAG] ) : false);
|
||||
|
||||
|
@ -2745,7 +2750,7 @@ function tag_deliver($uid, $item_id) {
|
|||
*/
|
||||
|
||||
if ($is_group && intval($item['item_thread_top']) && (! intval($item['item_wall']))) {
|
||||
if ((intval($term['ttype']) === TERM_FORUM || get_pconfig($uid,'system','post_via_mentions',in_array($role,['forum','forum_moderated']))) && perm_is_allowed($uid, $item['author_xchan'], 'post_wall')) {
|
||||
if ((intval($term['ttype']) === TERM_GROUP || get_pconfig($uid,'system','post_via_mentions',in_array($role,['forum','forum_moderated']))) && perm_is_allowed($uid, $item['author_xchan'], 'post_wall')) {
|
||||
logger('group mention delivery for ' . $u['channel_address']);
|
||||
start_delivery_chain($u, $item, $item_id, false, true, (($item['edited'] != $item['created']) || $item['item_deleted']));
|
||||
q("update item set item_blocked = %d where id = %d",
|
||||
|
@ -2835,7 +2840,7 @@ function tag_deliver($uid, $item_id) {
|
|||
*
|
||||
* @param number $uid A chnnel_id
|
||||
* @param array $item
|
||||
* @return boolean
|
||||
* @return boolean|string
|
||||
*/
|
||||
|
||||
function tgroup_check($uid, $item) {
|
||||
|
@ -2926,7 +2931,7 @@ function tgroup_check($uid, $item) {
|
|||
foreach ($terms as $term) {
|
||||
foreach ($followed_tags as $tag) {
|
||||
if (strcasecmp($term['term'],$tag) === 0) {
|
||||
$tag_result = true;
|
||||
$tag_result = $term['term'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2948,7 +2953,7 @@ function i_am_mentioned($channel,$item,$check_groups = false) {
|
|||
|
||||
$tagged = false;
|
||||
$matches = [];
|
||||
$tagtype = $check_groups ? TERM_FORUM : TERM_MENTION;
|
||||
$tagtype = $check_groups ? TERM_GROUP : TERM_MENTION;
|
||||
$terms = ((isset($item['term'])) ? get_terms_oftype($item['term'], $tagtype) : false);
|
||||
|
||||
if ($terms) {
|
||||
|
@ -4244,9 +4249,10 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
|
|||
}
|
||||
|
||||
if (! (isset($arr['include_follow']) && intval($arr['include_follow']))) {
|
||||
$item_normal .= " and not verb in ( 'Follow' , 'Ignore' ) ";
|
||||
$item_normal .= " and verb not in ( 'Follow' , 'Ignore' ) ";
|
||||
}
|
||||
|
||||
|
||||
if (isset($arr['star']) && $arr['star']) {
|
||||
$sql_options .= " and item_starred = 1 ";
|
||||
}
|
||||
|
@ -4413,6 +4419,11 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C
|
|||
$item_restrict = '';
|
||||
}
|
||||
|
||||
if (isset($arr['noadd']) && $arr['noadd']) {
|
||||
$item_restrict .= " and verb not in ('Add', 'Remove') ";
|
||||
}
|
||||
|
||||
|
||||
if (((isset($arr['compat']) && $arr['compat']) || ((isset($arr['nouveau']) && $arr['nouveau']) && ($client_mode & CLIENT_MODE_LOAD))) && $channel) {
|
||||
|
||||
// "New Item View" - show all items unthreaded in reverse created date order
|
||||
|
|
|
@ -2967,7 +2967,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
|
|||
$termtype = ((str_starts_with($tag, '#')) ? TERM_HASHTAG : TERM_UNKNOWN);
|
||||
$termtype = ((str_starts_with($tag, '"#')) ? TERM_HASHTAG : $termtype);
|
||||
$termtype = ((str_starts_with($tag, '@')) ? TERM_MENTION : $termtype);
|
||||
$termtype = ((str_starts_with($tag, '!')) ? TERM_FORUM : $termtype);
|
||||
$termtype = ((str_starts_with($tag, '!')) ? TERM_GROUP : $termtype);
|
||||
|
||||
// Is it a hashtag of some kind?
|
||||
|
||||
|
@ -3035,7 +3035,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
|
|||
|
||||
// BEGIN mentions
|
||||
|
||||
if (in_array($termtype, [TERM_MENTION, TERM_FORUM])) {
|
||||
if (in_array($termtype, [TERM_MENTION, TERM_GROUP])) {
|
||||
// The @! tag will alter permissions
|
||||
|
||||
// $in_network is set to false to avoid false positives on posts originating
|
||||
|
@ -3159,7 +3159,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
|
|||
}
|
||||
|
||||
// add the channel's xchan_hash to $access_tag if exclusive
|
||||
if ($exclusive) {
|
||||
if (($termtype === TERM_GROUP) || $exclusive) {
|
||||
$access_tag = 'cid:' . $xc['xchan_hash'];
|
||||
}
|
||||
|
||||
|
@ -3173,7 +3173,7 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
|
|||
|
||||
$zrl = isOWAEnabled($url) ? 'zrl' : 'url';
|
||||
|
||||
if ($termtype === TERM_FORUM) {
|
||||
if ($termtype === TERM_GROUP) {
|
||||
$newtag = '!' . (($exclusive) ? '!' : '') . '[' . $zrl . '=' . $profile . ']' . $newname . '[/' . $zrl . ']';
|
||||
$body = str_replace('!' . (($exclusive) ? '!' : '') . $name, $newtag, $body);
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ function format_term_for_display($term)
|
|||
$s = '';
|
||||
if (($term['ttype'] == TERM_HASHTAG) || ($term['ttype'] == TERM_COMMUNITYTAG)) {
|
||||
$s .= '#';
|
||||
} elseif ($term['ttype'] == TERM_FORUM) {
|
||||
} elseif ($term['ttype'] == TERM_GROUP) {
|
||||
$s .= '!';
|
||||
} elseif ($term['ttype'] == TERM_MENTION) {
|
||||
$s .= '@';
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Code\Web;
|
|||
* @brief The main entry point to the application.
|
||||
*/
|
||||
|
||||
require_once 'Code/Web/WebServer.php';
|
||||
require_once 'src/Web/WebServer.php';
|
||||
|
||||
$server = new WebServer();
|
||||
$server->run();
|
||||
|
|
|
@ -214,14 +214,14 @@ using web forms.
|
|||
8. Set up a cron job or scheduled task to run the Cron manager once every 10-15
|
||||
minutes to perform background processing and maintenance. Example:
|
||||
|
||||
cd /base/directory; /path/to/php Code/Daemon/Run.php Cron
|
||||
cd /base/directory; /path/to/php src/Daemon/Run.php Cron
|
||||
|
||||
Change "/base/directory", and "/path/to/php" as appropriate for your situation.
|
||||
|
||||
If you are using a Linux server, run "crontab -e" and add a line like the
|
||||
one shown, substituting for your unique paths and settings:
|
||||
|
||||
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php Code/Daemon/Run.php Cron > /dev/null 2>&1
|
||||
*/10 * * * * cd /home/myname/mywebsite; /usr/bin/php src/Daemon/Run.php Cron > /dev/null 2>&1
|
||||
|
||||
You can generally find the location of PHP by executing "which php". If you
|
||||
have troubles with this section please contact your hosting provider for
|
||||
|
|
|
@ -617,8 +617,8 @@ CREATE TABLE IF NOT EXISTS `item` (
|
|||
`item_delayed` tinyint NOT NULL DEFAULT 0 ,
|
||||
`item_pending_remove` tinyint NOT NULL DEFAULT 0 ,
|
||||
`item_blocked` tinyint NOT NULL DEFAULT 0 ,
|
||||
`lat` float NOT NULL DEFAULT '0',
|
||||
`lon` float NOT NULL DEFAULT '0',
|
||||
`lat` double NOT NULL DEFAULT '0',
|
||||
`lon` double NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `parent` (`parent`),
|
||||
KEY `created` (`created`),
|
||||
|
@ -1161,6 +1161,7 @@ CREATE TABLE IF NOT EXISTS `verify` (
|
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `xchan` (
|
||||
`xchan_id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`xchan_hash` varchar(255) NOT NULL,
|
||||
`xchan_guid` varchar(255) NOT NULL DEFAULT '',
|
||||
`xchan_guid_sig` text NOT NULL,
|
||||
|
@ -1188,7 +1189,8 @@ CREATE TABLE IF NOT EXISTS `xchan` (
|
|||
`xchan_system` tinyint NOT NULL DEFAULT 0 ,
|
||||
`xchan_type` tinyint NOT NULL DEFAULT 0 ,
|
||||
`xchan_deleted` tinyint NOT NULL DEFAULT 0 ,
|
||||
PRIMARY KEY (`xchan_hash`(191)),
|
||||
PRIMARY KEY (`xchan_id`),
|
||||
UNIQUE `xchan_hash` (`xchan_hash`(191)),
|
||||
KEY `xchan_guid` (`xchan_guid`(191)),
|
||||
KEY `xchan_addr` (`xchan_addr`(191)),
|
||||
KEY `xchan_name` (`xchan_name`(191)),
|
||||
|
|
|
@ -631,8 +631,8 @@ CREATE TABLE "item" (
|
|||
"item_delayed" smallint NOT NULL DEFAULT '0',
|
||||
"item_pending_remove" smallint NOT NULL DEFAULT '0',
|
||||
"item_blocked" smallint NOT NULL DEFAULT '0',
|
||||
"lat" float NOT NULL DEFAULT '0',
|
||||
"lon" float NOT NULL DEFAULT '0',
|
||||
"lat" double NOT NULL DEFAULT '0',
|
||||
"lon" double NOT NULL DEFAULT '0',
|
||||
"item_search_vector" tsvector,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
@ -1230,6 +1230,7 @@ create index "vote_guid" on vote ("vote_guid");
|
|||
create index "vote_poll" on vote ("vote_poll");
|
||||
create index "vote_element" on vote ("vote_element");
|
||||
CREATE TABLE "xchan" (
|
||||
"xchan_id" serial NOT NULL,
|
||||
"xchan_hash" text NOT NULL,
|
||||
"xchan_guid" text NOT NULL DEFAULT '',
|
||||
"xchan_guid_sig" text NOT NULL DEFAULT '',
|
||||
|
@ -1257,8 +1258,9 @@ CREATE TABLE "xchan" (
|
|||
"xchan_system" smallint NOT NULL DEFAULT '0',
|
||||
"xchan_type" smallint NOT NULL DEFAULT '0',
|
||||
"xchan_deleted" smallint NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY ("xchan_hash")
|
||||
PRIMARY KEY ("xchan_id")
|
||||
);
|
||||
create unique index "xchan_hash" on xchan ("xchan_hash");
|
||||
create index "xchan_guid" on xchan ("xchan_guid");
|
||||
create index "xchan_addr" on xchan ("xchan_addr");
|
||||
create index "xchan_name" on xchan ("xchan_name");
|
||||
|
|
|
@ -112,7 +112,7 @@ jquery.i18n:
|
|||
min:
|
||||
[echo] Building ./jquery.i18n.min.js
|
||||
[apply] Applied java to 1 file and 0 directories.
|
||||
[delete] Deleting: /Users/dave/Documents/Code/jquery/jquery-i18n/tmpmin
|
||||
[delete] Deleting: /Users/dave/Documents/src/jquery/jquery-i18n/tmpmin
|
||||
[echo] ./jquery.i18n.min.js built.
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
|
|
40
library/sodium-plus/.github/workflows/main.yml
vendored
Normal file
40
library/sodium-plus/.github/workflows/main.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
platform: [ubuntu-latest]
|
||||
node: [ '12', '10' ]
|
||||
name: Node ${{ matrix.node }} (${{ matrix.platform }})
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- name: install dependencies
|
||||
run: npm install
|
||||
- name: test without sodium-native
|
||||
run: npm test
|
||||
- name: install sodium-native
|
||||
run: npm install --save sodium-native
|
||||
- name: test with sodium-native
|
||||
run: npm test
|
||||
|
||||
build_latest:
|
||||
name: Node latest
|
||||
runs-on: ubuntu-latest
|
||||
container: node:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: install dependencies
|
||||
run: npm install
|
||||
- name: test without sodium-native
|
||||
run: npm test
|
||||
- name: install sodium-native
|
||||
run: npm install --save sodium-native
|
||||
- name: test with sodium-native
|
||||
run: npm test
|
6
library/sodium-plus/.gitignore
vendored
Normal file
6
library/sodium-plus/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
/.idea
|
||||
/node_modules
|
||||
/package-lock.json
|
||||
*-tmp.js
|
||||
/nbproject
|
||||
/.nyc_output
|
3
library/sodium-plus/.npmignore
Normal file
3
library/sodium-plus/.npmignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
/.idea
|
||||
/dist
|
||||
*-tmp.js
|
18
library/sodium-plus/LICENSE
Normal file
18
library/sodium-plus/LICENSE
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* ISC License
|
||||
*
|
||||
* Copyright (c) 2019
|
||||
* Paragon Initiative Enterprises <security at paragonie dot com>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
86
library/sodium-plus/README.md
Normal file
86
library/sodium-plus/README.md
Normal file
|
@ -0,0 +1,86 @@
|
|||
# Sodium-Plus (Na+)
|
||||
|
||||
[![Build Status](https://github.com/paragonie/sodium-plus/workflows/CI/badge.svg)](https://github.com/paragonie/sodium-plus/actions?workflow=CI)
|
||||
[![npm version](https://img.shields.io/npm/v/sodium-plus.svg)](https://npm.im/sodium-plus)
|
||||
|
||||
Sodium-Plus delivers a positive cryptography experience for JavaScript developers.
|
||||
|
||||
Sodium-Plus brings you all the benefits of using libsodium in your application
|
||||
without any of the headaches introduced by the incumbent APIs.
|
||||
|
||||
Sodium-Plus is permissively licensed (ISC) and free to use.
|
||||
|
||||
## Features
|
||||
|
||||
* **Cross-platform.**
|
||||
* Yes, this includes [in the browser](docs/getting-started.md#sodium-plus-in-the-browser).
|
||||
* Pluggable backend with an [auto-loader](docs/getting-started.md):
|
||||
* If [sodium-native](https://github.com/sodium-friends/sodium-native)
|
||||
is installed, it will be preferred.
|
||||
* Otherwise, the default is [libsodium-wrappers](https://github.com/jedisct1/libsodium.js).
|
||||
* Fully `async`/`await` ready (aside from object constructors).
|
||||
* Type-safe API:
|
||||
* Instead of just passing around `Buffer` objects and hoping you got your
|
||||
argument order correct, `sodium-plus` will throw an Error if you provide
|
||||
the wrong key type. This prevents you from accidentally introducing a severe
|
||||
security risk into your application.
|
||||
|
||||
## Installing
|
||||
|
||||
### Installing as a Node.js Module
|
||||
|
||||
With NPM:
|
||||
|
||||
```terminal
|
||||
npm install sodium-plus
|
||||
```
|
||||
|
||||
You can optionally install `sodium-native` alongside `sodium-plus` if you
|
||||
want better performance.
|
||||
|
||||
The default configuration is a bit slower, but has a wider reach
|
||||
(e.g. web browsers).
|
||||
|
||||
### Installing in a Web Page
|
||||
|
||||
See [this section of the documentation](docs/getting-started.md#sodium-plus-in-the-browser)
|
||||
for getting started with Sodium-Plus in a web browser.
|
||||
|
||||
## Using Sodium-Plus in Your Projects
|
||||
|
||||
SodiumPlus is meant to be used asynchronously, like so:
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
|
||||
(async function() {
|
||||
// Select a backend automatically
|
||||
let sodium = await SodiumPlus.auto();
|
||||
|
||||
let key = await sodium.crypto_secretbox_keygen();
|
||||
let nonce = await sodium.randombytes_buf(24);
|
||||
let message = 'This is just a test message';
|
||||
// Message can be a string, buffer, array, etc.
|
||||
|
||||
let ciphertext = await sodium.crypto_secretbox(message, nonce, key);
|
||||
console.log(ciphertext);
|
||||
let decrypted = await sodium.crypto_secretbox_open(ciphertext, nonce, key);
|
||||
console.log(decrypted.toString('utf-8'));
|
||||
})();
|
||||
```
|
||||
|
||||
This should produce output similar to below (but with different random-looking bytes):
|
||||
|
||||
```
|
||||
<Buffer 00 b7 66 89 3d b4 4d e9 7e 0f 66 91 fd d1 ca fd be bb 7f 00 89 76 5b 48 ec ed 80 cc 87 76 54 1b b5 ea 87 9b e5 19 ee 4c 31 c5 63>
|
||||
This is just a test message
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation is [available online on Github](https://github.com/paragonie/sodium-plus/tree/master/docs)!
|
||||
|
||||
## Support Contracts
|
||||
|
||||
If your company uses this library in their products or services, you may be
|
||||
interested in [purchasing a support contract from Paragon Initiative Enterprises](https://paragonie.com/enterprise).
|
25
library/sodium-plus/browser.js
Normal file
25
library/sodium-plus/browser.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
const {
|
||||
CryptographyKey,
|
||||
Ed25519PublicKey,
|
||||
Ed25519SecretKey,
|
||||
SodiumError,
|
||||
SodiumPlus,
|
||||
SodiumPolyfill,
|
||||
SodiumUtil,
|
||||
X25519PublicKey,
|
||||
X25519SecretKey
|
||||
} = require('./index');
|
||||
|
||||
// Load dependencies into window
|
||||
(async function(){
|
||||
window.CryptographyKey = CryptographyKey;
|
||||
window.Ed25519PublicKey = Ed25519PublicKey;
|
||||
window.Ed25519SecretKey = Ed25519SecretKey;
|
||||
window.SodiumError = SodiumError;
|
||||
window.SodiumPlus = SodiumPlus;
|
||||
window.SodiumPolyfill = SodiumPolyfill;
|
||||
window.SodiumUtil = SodiumUtil;
|
||||
window.X25519PublicKey = X25519PublicKey;
|
||||
window.X25519SecretKey = X25519SecretKey;
|
||||
window.sodium = await SodiumPlus.auto();
|
||||
})();
|
22
library/sodium-plus/build.sh
Normal file
22
library/sodium-plus/build.sh
Normal file
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
basedir=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
|
||||
path="${basedir}/build/remove-sodium-native.sh"
|
||||
|
||||
bash "${path}"
|
||||
ret=$?
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
echo "Exiting..."
|
||||
exit "${ret}"
|
||||
fi
|
||||
|
||||
echo "Building..."
|
||||
browserify browser.js > dist/sodium-plus.js
|
||||
echo "Minifying..."
|
||||
browserify browser.js -p tinyify > dist/sodium-plus.min.js
|
||||
echo "Build complete! Resetting..."
|
||||
|
||||
# Once browserify finishes, rollback changes that removed sodium-native.
|
||||
git checkout -- lib/*
|
||||
git checkout -- lib/*/*
|
||||
echo "Done!"
|
57
library/sodium-plus/build/pre-build.patch
Normal file
57
library/sodium-plus/build/pre-build.patch
Normal file
|
@ -0,0 +1,57 @@
|
|||
diff --git a/lib/backend/sodiumnative.js b/lib/backend/sodiumnative.js
|
||||
index a592b10..f268085 100644
|
||||
--- a/lib/backend/sodiumnative.js
|
||||
+++ b/lib/backend/sodiumnative.js
|
||||
@@ -1,12 +1,5 @@
|
||||
let loaded = false;
|
||||
-let _sodium;
|
||||
-/* istanbul ignore next */
|
||||
-try {
|
||||
- _sodium = require('sodium-native');
|
||||
- loaded = true;
|
||||
-} catch (e) {
|
||||
- _sodium = {};
|
||||
-}
|
||||
+let _sodium = {};
|
||||
const Backend = require('../backend');
|
||||
const CryptographyKey = require('../cryptography-key');
|
||||
const SodiumError = require('../sodium-error');
|
||||
diff --git a/lib/sodiumplus.js b/lib/sodiumplus.js
|
||||
index a592b10..f268085 100644
|
||||
--- a/lib/sodiumplus.js
|
||||
+++ b/lib/sodiumplus.js
|
||||
@@ -4,7 +4,6 @@
|
||||
const Ed25519PublicKey = require('./keytypes/ed25519pk');
|
||||
const LibsodiumWrappersBackend = require('./backend/libsodium-wrappers');
|
||||
const SodiumError = require('./sodium-error');
|
||||
-const SodiumNativeBackend = require('./backend/sodiumnative');
|
||||
const X25519PublicKey = require('./keytypes/x25519pk');
|
||||
const X25519SecretKey = require('./keytypes/x25519sk');
|
||||
const Util = require('./util');
|
||||
@@ -41,7 +40,7 @@
|
||||
* @return {boolean}
|
||||
*/
|
||||
isSodiumNative() {
|
||||
- return (this.backend instanceof SodiumNativeBackend);
|
||||
+ return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,16 +59,7 @@
|
||||
* @return {Promise<SodiumPlus>}
|
||||
*/
|
||||
static async auto() {
|
||||
- let backend;
|
||||
- try {
|
||||
- backend = await SodiumNativeBackend.init();
|
||||
- } catch (e) {
|
||||
- backend = await LibsodiumWrappersBackend.init();
|
||||
- }
|
||||
- /* istanbul ignore if */
|
||||
- if (!backend) {
|
||||
- backend = await LibsodiumWrappersBackend.init();
|
||||
- }
|
||||
+ let backend = await LibsodiumWrappersBackend.init();
|
||||
Util.populateConstants(backend);
|
||||
return new SodiumPlus(backend);
|
||||
}
|
12
library/sodium-plus/build/remove-sodium-native.sh
Normal file
12
library/sodium-plus/build/remove-sodium-native.sh
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
basedir=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
|
||||
path="${basedir}/pre-build.patch"
|
||||
|
||||
git apply --check "${path}"
|
||||
ret=$?
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
exit "${ret}"
|
||||
fi
|
||||
git apply "${path}"
|
||||
ret=$?
|
||||
exit $ret
|
30454
library/sodium-plus/dist/sodium-plus.js
vendored
Normal file
30454
library/sodium-plus/dist/sodium-plus.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
library/sodium-plus/dist/sodium-plus.min.js
vendored
Normal file
1
library/sodium-plus/dist/sodium-plus.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
99
library/sodium-plus/docs/README.md
Normal file
99
library/sodium-plus/docs/README.md
Normal file
|
@ -0,0 +1,99 @@
|
|||
# Table of Contents
|
||||
|
||||
* [Table of Contents](#table-of-contents) (you are here)
|
||||
* [Getting Started](getting-started.md#getting-started)
|
||||
* [CryptographyKey](getting-started.md#cryptographykey)
|
||||
* [Sodium-Plus in the Browser](getting-started.md#sodium-plus-in-the-browser)
|
||||
* [SodiumPlus Methods](SodiumPlus#sodiumplus-methods)
|
||||
* [AEAD (XChaCha20-Poly1305)](SodiumPlus/AEAD.md#aead)
|
||||
* [crypto_aead_xchacha20poly1305_ietf_decrypt](SodiumPlus/AEAD.md#crypto_aead_xchacha20poly1305_ietf_decrypt)
|
||||
* [crypto_aead_xchacha20poly1305_ietf_encrypt](SodiumPlus/AEAD.md#crypto_aead_xchacha20poly1305_ietf_encrypt)
|
||||
* [crypto_aead_xchacha20poly1305_ietf_keygen](SodiumPlus/AEAD.md#crypto_aead_xchacha20poly1305_ietf_keygen)
|
||||
* [Example for crypto_aead_xchacha20poly1305_ietf_*](SodiumPlus/AEAD.md#example-for-crypto_aead_xchacha20poly1305_ietf_)
|
||||
* [Shared-key authentication](SodiumPlus/shared-key-authentication.md)
|
||||
* [crypto_auth](SodiumPlus/shared-key-authentication.md#crypto_auth)
|
||||
* [crypto_auth_verify](SodiumPlus/shared-key-authentication.md#crypto_auth_verify)
|
||||
* [crypto_auth_keygen](SodiumPlus/shared-key-authentication.md#crypto_auth_keygen)
|
||||
* [Example for crypto_auth](SodiumPlus/shared-key-authentication.md#example-for-crypto_auth)
|
||||
* [Authenticated public-key encryption](SodiumPlus/authenticated-public-key-encryption.md)
|
||||
* [crypto_box](SodiumPlus/authenticated-public-key-encryption.md#crypto_box)
|
||||
* [crypto_box_open](SodiumPlus/authenticated-public-key-encryption.md#crypto_box_open)
|
||||
* [crypto_box_keypair](SodiumPlus/authenticated-public-key-encryption.md#crypto_box_keypair)
|
||||
* [crypto_box_keypair_from_secretkey_and_publickey](SodiumPlus/authenticated-public-key-encryption.md#crypto_box_keypair_from_secretkey_and_publickey)
|
||||
* [crypto_box_publickey](SodiumPlus/authenticated-public-key-encryption.md#crypto_box_publickey)
|
||||
* [crypto_box_secretkey](SodiumPlus/authenticated-public-key-encryption.md#crypto_box_secretkey)
|
||||
* [crypto_box_publickey_from_secretkey](SodiumPlus/authenticated-public-key-encryption.md#crypto_box_publickey_from_secretkey)
|
||||
* [Example for crypto_box](SodiumPlus/authenticated-public-key-encryption.md#example-for-crypto_box)
|
||||
* [Sealed boxes (anonymous public-key encryption)](SodiumPlus/sealed-boxes.md)
|
||||
* [crypto_box_seal](SodiumPlus/sealed-boxes.md#crypto_box_seal)
|
||||
* [crypto_box_seal_open](SodiumPlus/sealed-boxes.md#crypto_box_seal_open)
|
||||
* [Example for crypto_box_seal](SodiumPlus/sealed-boxes.md#example-for-crypto_box_seal)
|
||||
* [General-purpose cryptographic hash](SodiumPlus/general-purpose-cryptographic-hash.md)
|
||||
* [crypto_generichash](SodiumPlus/general-purpose-cryptographic-hash.md#crypto_generichash)
|
||||
* [crypto_generichash_init](SodiumPlus/general-purpose-cryptographic-hash.md#crypto_generichash_init)
|
||||
* [crypto_generichash_update](SodiumPlus/general-purpose-cryptographic-hash.md#crypto_generichash_update)
|
||||
* [crypto_generichash_final](SodiumPlus/general-purpose-cryptographic-hash.md#crypto_generichash_final)
|
||||
* [crypto_generichash_keygen](SodiumPlus/general-purpose-cryptographic-hash.md#crypto_generichash_keygen)
|
||||
* [Example for crypto_generichash](SodiumPlus/general-purpose-cryptographic-hash.md#example-for-crypto_generichash)
|
||||
* [Key derivation](SodiumPlus/key-derivation.md)
|
||||
* [crypto_kdf_derive_from_key](SodiumPlus/key-derivation.md#crypto_kdf_derive_from_key)
|
||||
* [crypto_kdf_keygen](SodiumPlus/key-derivation.md#crypto_kdf_keygen)
|
||||
* [Example for crypto_kdf](SodiumPlus/key-derivation.md#example-for-crypto_kdf)
|
||||
* [Key exchange](SodiumPlus/key-exchange.md)
|
||||
* [crypto_kx_keypair](SodiumPlus/key-exchange.md#crypto_kx_keypair)
|
||||
* [crypto_kx_seed_keypair](SodiumPlus/key-exchange.md#crypto_kx_seed_keypair)
|
||||
* [crypto_kx_client_session_keys](SodiumPlus/key-exchange.md#crypto_kx_client_session_keys)
|
||||
* [crypto_kx_server_session_keys](SodiumPlus/key-exchange.md#crypto_kx_server_session_keys)
|
||||
* [Example for crypto_kx](SodiumPlus/key-exchange.md#example-for-crypto_kx)
|
||||
* [One-time authentication](SodiumPlus/one-time-authentication.md)
|
||||
* [crypto_onetimeauth](SodiumPlus/one-time-authentication.md#crypto_onetimeauth)
|
||||
* [crypto_onetimeauth_verify](SodiumPlus/one-time-authentication.md#crypto_onetimeauth_verify)
|
||||
* [crypto_onetimeauth_keygen](SodiumPlus/one-time-authentication.md#crypto_onetimeauth_keygen)
|
||||
* [Example for crypto_onetimeauth](SodiumPlus/one-time-authentication.md#example-for-crypto_onetimeauth)
|
||||
* [Password-based key derivation](SodiumPlus/password-based-key-derivation.md)
|
||||
* [crypto_pwhash](SodiumPlus/password-based-key-derivation.md#crypto_pwhash)
|
||||
* [Example for crypto_pwhash](SodiumPlus/password-based-key-derivation.md#example-for-crypto_pwhash)
|
||||
* [Password hashing and storage](SodiumPlus/password-hashing-and-storage.md)
|
||||
* [crypto_pwhash_str](SodiumPlus/password-hashing-and-storage.md#crypto_pwhash_str)
|
||||
* [crypto_pwhash_str_needs_rehash](SodiumPlus/password-hashing-and-storage.md#crypto_pwhash_str_needs_rehash)
|
||||
* [crypto_pwhash_str_verify](SodiumPlus/password-hashing-and-storage.md#crypto_pwhash_str_verify)
|
||||
* [Example for crypto_pwhash_str](SodiumPlus/password-hashing-and-storage.md#example-for-crypto_pwhash_str)
|
||||
* [Scalar multiplication over Curve25519 (advanced)](SodiumPlus/scalar-multiplication.md)
|
||||
* [crypto_scalarmult](SodiumPlus/scalar-multiplication.md#crypto_scalarmult)
|
||||
* [crypto_scalarmult_base](SodiumPlus/scalar-multiplication.md#crypto_scalarmult_base)
|
||||
* [Example for crypto_scalarmult](SodiumPlus/scalar-multiplication.md#example-for-crypto_scalarmult)
|
||||
* [Shared-key authenticated encryption](SodiumPlus/shared-key-authenticated-encryption.md)
|
||||
* [crypto_secretbox](SodiumPlus/shared-key-authenticated-encryption.md#crypto_secretbox)
|
||||
* [crypto_secretbox_open](SodiumPlus/shared-key-authenticated-encryption.md#crypto_secretbox_open)
|
||||
* [crypto_secretbox_keygen](SodiumPlus/shared-key-authenticated-encryption.md#crypto_secretbox_keygen)
|
||||
* [Example for crypto_secretbox](SodiumPlus/shared-key-authenticated-encryption.md#example-for-crypto_secretbox)
|
||||
* [Encrypted streams](SodiumPlus/encrypted-streams.md)
|
||||
* [crypto_secretstream_xchacha20poly1305_init_push](SodiumPlus/encrypted-streams.md#crypto_secretstream_xchacha20poly1305_init_push)
|
||||
* [crypto_secretstream_xchacha20poly1305_init_pull](SodiumPlus/encrypted-streams.md#crypto_secretstream_xchacha20poly1305_init_pull)
|
||||
* [crypto_secretstream_xchacha20poly1305_push](SodiumPlus/encrypted-streams.md#crypto_secretstream_xchacha20poly1305_push)
|
||||
* [crypto_secretstream_xchacha20poly1305_pull](SodiumPlus/encrypted-streams.md#crypto_secretstream_xchacha20poly1305_pull)
|
||||
* [crypto_secretstream_xchacha20poly1305_keygen](SodiumPlus/encrypted-streams.md#crypto_secretstream_xchacha20poly1305_keygen)
|
||||
* [crypto_secretstream_xchacha20poly1305_rekey](SodiumPlus/encrypted-streams.md#crypto_secretstream_xchacha20poly1305_rekey)
|
||||
* [Example for crypto_secretstream_xchacha20poly1305](SodiumPlus/encrypted-streams.md#example-for-crypto_secretstream_xchacha20poly1305)
|
||||
* [Short-input hashing](SodiumPlus/short-input-hashing.md)
|
||||
* [crypto_shorthash](SodiumPlus/short-input-hashing.md#crypto_shorthash)
|
||||
* [crypto_shorthash_keygen](SodiumPlus/short-input-hashing.md#crypto_shorthash_keygen)
|
||||
* [Example for crypto_shorthash](SodiumPlus/short-input-hashing.md#example-for-crypto_shorthash)
|
||||
* [Digital signatures](SodiumPlus/digital-signatures.md)
|
||||
* [crypto_sign](SodiumPlus/digital-signatures.md#crypto_sign)
|
||||
* [crypto_sign_open](SodiumPlus/digital-signatures.md#crypto_sign_open)
|
||||
* [crypto_sign_detached](SodiumPlus/digital-signatures.md#crypto_sign_detached)
|
||||
* [crypto_sign_verify_detached](SodiumPlus/digital-signatures.md#crypto_sign_verify_detached)
|
||||
* [crypto_sign_keypair](SodiumPlus/digital-signatures.md#crypto_sign_keypair)
|
||||
* [crypto_sign_publickey](SodiumPlus/digital-signatures.md#crypto_sign_publickey)
|
||||
* [crypto_sign_secretkey](SodiumPlus/digital-signatures.md#crypto_sign_secretkey)
|
||||
* [crypto_sign_ed25519_sk_to_curve25519](SodiumPlus/digital-signatures.md#crypto_sign_ed25519_sk_to_curve25519)
|
||||
* [crypto_sign_ed25519_pk_to_curve25519](SodiumPlus/digital-signatures.md#crypto_sign_ed25519_pk_to_curve25519)
|
||||
* [Example for crypto_sign](SodiumPlus/digital-signatures.md#example-for-crypto_sign)
|
||||
* [Randomness](SodiumPlus/randomness.md)
|
||||
* [randombytes_buf](SodiumPlus/randomness.md#randombytes_buf)
|
||||
* [randombytes_uniform](SodiumPlus/randomness.md#randombytes_uniform)
|
||||
* [Example for randombytes](SodiumPlus/randomness.md#example-for-randombytes)
|
||||
* [Utilities](SodiumPlus/utilities.md)
|
||||
* [sodium_bin2hex](SodiumPlus/utilities.md#sodium_bin2hex)
|
||||
* [sodium_hex2bin](SodiumPlus/utilities.md#sodium_bin2hex)
|
64
library/sodium-plus/docs/SodiumPlus/AEAD.md
Normal file
64
library/sodium-plus/docs/SodiumPlus/AEAD.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
## AEAD
|
||||
|
||||
> **See also:** [Libsodium's documentation on its AEAD features](https://download.libsodium.org/doc/secret-key_cryptography/aead/chacha20-poly1305/xchacha20-poly1305_construction).
|
||||
|
||||
### crypto_aead_xchacha20poly1305_ietf_decrypt
|
||||
|
||||
Decrypt a message (and optional associated data) with XChaCha20-Poly1305.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` Ciphertext
|
||||
2. `{string|Buffer}` nonce (must be 24 bytes)
|
||||
3. `{CryptographyKey}` key
|
||||
4. `{string|Buffer}` assocData
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
Throws a `SodiumError` on decryption failure.
|
||||
|
||||
### crypto_aead_xchacha20poly1305_ietf_encrypt
|
||||
|
||||
Encrypt a message (and optional associated data) with XChaCha20-Poly1305.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` Plaintext
|
||||
2. `{string|Buffer}` nonce (must be 24 bytes)
|
||||
3. `{CryptographyKey}` key
|
||||
4. `{string|Buffer}` assocData
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_aead_xchacha20poly1305_ietf_keygen
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_aead_xchacha20poly1305_ietf_` API.
|
||||
|
||||
### Example for crypto_aead_xchacha20poly1305_ietf_*
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = 'Your message goes here';
|
||||
let key = await sodium.crypto_aead_xchacha20poly1305_ietf_keygen();
|
||||
let nonce = await sodium.randombytes_buf(24);
|
||||
let ciphertext = await sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
plaintext,
|
||||
nonce,
|
||||
key
|
||||
);
|
||||
|
||||
console.log(ciphertext.toString('hex'));
|
||||
|
||||
let decrypted = await sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
ciphertext,
|
||||
nonce,
|
||||
key
|
||||
);
|
||||
|
||||
console.log(decrypted.toString());
|
||||
})();
|
||||
```
|
99
library/sodium-plus/docs/SodiumPlus/README.md
Normal file
99
library/sodium-plus/docs/SodiumPlus/README.md
Normal file
|
@ -0,0 +1,99 @@
|
|||
# SodiumPlus Methods
|
||||
|
||||
This describes the methods in the public API for Sodium-Plus.
|
||||
If you're not sure which method to use, please refer to the
|
||||
[Libsodium Quick Reference](https://paragonie.com/blog/2017/06/libsodium-quick-reference-quick-comparison-similar-functions-and-which-one-use)
|
||||
for guidance.
|
||||
|
||||
* [AEAD (XChaCha20-Poly1305)](AEAD.md#aead)
|
||||
* [crypto_aead_xchacha20poly1305_ietf_decrypt](AEAD.md#crypto_aead_xchacha20poly1305_ietf_decrypt)
|
||||
* [crypto_aead_xchacha20poly1305_ietf_encrypt](AEAD.md#crypto_aead_xchacha20poly1305_ietf_encrypt)
|
||||
* [crypto_aead_xchacha20poly1305_ietf_keygen](AEAD.md#crypto_aead_xchacha20poly1305_ietf_keygen)
|
||||
* [Example for crypto_aead_xchacha20poly1305_ietf_*](AEAD.md#example-for-crypto_aead_xchacha20poly1305_ietf_)
|
||||
* [Shared-key authentication](shared-key-authentication.md)
|
||||
* [crypto_auth](shared-key-authentication.md#crypto_auth)
|
||||
* [crypto_auth_verify](shared-key-authentication.md#crypto_auth_verify)
|
||||
* [crypto_auth_keygen](shared-key-authentication.md#crypto_auth_keygen)
|
||||
* [Example for crypto_auth](shared-key-authentication.md#example-for-crypto_auth)
|
||||
* [Authenticated public-key encryption](authenticated-public-key-encryption.md)
|
||||
* [crypto_box](authenticated-public-key-encryption.md#crypto_box)
|
||||
* [crypto_box_open](authenticated-public-key-encryption.md#crypto_box_open)
|
||||
* [crypto_box_keypair](authenticated-public-key-encryption.md#crypto_box_keypair)
|
||||
* [crypto_box_keypair_from_secretkey_and_secretkey](authenticated-public-key-encryption.md#crypto_box_keypair_from_secretkey_and_secretkey)
|
||||
* [crypto_box_publickey](authenticated-public-key-encryption.md#crypto_box_publickey)
|
||||
* [crypto_box_secretkey](authenticated-public-key-encryption.md#crypto_box_secretkey)
|
||||
* [crypto_box_publickey_from_secretkey](authenticated-public-key-encryption.md#crypto_box_publickey_from_secretkey)
|
||||
* [Example for crypto_box](authenticated-public-key-encryption.md#example-for-crypto_box)
|
||||
* [Sealed boxes (anonymous public-key encryption)](sealed-boxes.md)
|
||||
* [crypto_box_seal](sealed-boxes.md#crypto_box_seal)
|
||||
* [crypto_box_seal_open](sealed-boxes.md#crypto_box_seal_open)
|
||||
* [Example for crypto_box_seal](sealed-boxes.md#example-for-crypto_box_seal)
|
||||
* [General-purpose cryptographic hash](general-purpose-cryptographic-hash.md)
|
||||
* [crypto_generichash](general-purpose-cryptographic-hash.md#crypto_generichash)
|
||||
* [crypto_generichash_init](general-purpose-cryptographic-hash.md#crypto_generichash_init)
|
||||
* [crypto_generichash_update](general-purpose-cryptographic-hash.md#crypto_generichash_update)
|
||||
* [crypto_generichash_final](general-purpose-cryptographic-hash.md#crypto_generichash_final)
|
||||
* [crypto_generichash_keygen](general-purpose-cryptographic-hash.md#crypto_generichash_keygen)
|
||||
* [Example for crypto_generichash](general-purpose-cryptographic-hash.md#example-for-crypto_generichash)
|
||||
* [Key derivation](key-derivation.md)
|
||||
* [crypto_kdf_derive_from_key](key-derivation.md#crypto_kdf_derive_from_key)
|
||||
* [crypto_kdf_keygen](key-derivation.md#crypto_kdf_keygen)
|
||||
* [Example for crypto_kdf](key-derivation.md#example-for-crypto_kdf)
|
||||
* [Key exchange](key-exchange.md)
|
||||
* [crypto_kx_keypair](key-exchange.md#crypto_kx_keypair)
|
||||
* [crypto_kx_seed_keypair](key-exchange.md#crypto_kx_seed_keypair)
|
||||
* [crypto_kx_client_session_keys](key-exchange.md#crypto_kx_client_session_keys)
|
||||
* [crypto_kx_server_session_keys](key-exchange.md#crypto_kx_server_session_keys)
|
||||
* [Example for crypto_kx](key-exchange.md#example-for-crypto_kx)
|
||||
* [One-time authentication](one-time-authentication.md)
|
||||
* [crypto_onetimeauth](one-time-authentication.md#crypto_onetimeauth)
|
||||
* [crypto_onetimeauth_verify](one-time-authentication.md#crypto_onetimeauth_verify)
|
||||
* [crypto_onetimeauth_keygen](one-time-authentication.md#crypto_onetimeauth_keygen)
|
||||
* [Example for crypto_onetimeauth](one-time-authentication.md#example-for-crypto_onetimeauth)
|
||||
* [Password-based key derivation](password-based-key-derivation.md)
|
||||
* [crypto_pwhash](password-based-key-derivation.md#crypto_pwhash)
|
||||
* [Example for crypto_pwhash](password-based-key-derivation.md#example-for-crypto_pwhash)
|
||||
* [Password hashing and storage](password-hashing-and-storage.md)
|
||||
* [crypto_pwhash_str](password-hashing-and-storage.md#crypto_pwhash_str)
|
||||
* [crypto_pwhash_str_needs_rehash](password-hashing-and-storage.md#crypto_pwhash_str_needs_rehash)
|
||||
* [crypto_pwhash_str_verify](password-hashing-and-storage.md#crypto_pwhash_str_verify)
|
||||
* [Example for crypto_pwhash_str](password-hashing-and-storage.md#example-for-crypto_pwhash_str)
|
||||
* [Scalar multiplication over Curve25519 (advanced)](scalar-multiplication.md)
|
||||
* [crypto_scalarmult](scalar-multiplication.md#crypto_scalarmult)
|
||||
* [crypto_scalarmult_base](scalar-multiplication.md#crypto_scalarmult_base)
|
||||
* [Example for crypto_scalarmult](scalar-multiplication.md#example-for-crypto_scalarmult)
|
||||
* [Shared-key authenticated encryption](shared-key-authenticated-encryption.md)
|
||||
* [crypto_secretbox](shared-key-authenticated-encryption.md#crypto_secretbox)
|
||||
* [crypto_secretbox_open](shared-key-authenticated-encryption.md#crypto_secretbox_open)
|
||||
* [crypto_secretbox_keygen](shared-key-authenticated-encryption.md#crypto_secretbox_keygen)
|
||||
* [Example for crypto_secretbox](shared-key-authenticated-encryption.md#example-for-crypto_secretbox)
|
||||
* [Encrypted streams](encrypted-streams.md)
|
||||
* [crypto_secretstream_xchacha20poly1305_init_push](encrypted-streams.md#crypto_secretstream_xchacha20poly1305_init_push)
|
||||
* [crypto_secretstream_xchacha20poly1305_init_pull](encrypted-streams.md#crypto_secretstream_xchacha20poly1305_init_pull)
|
||||
* [crypto_secretstream_xchacha20poly1305_push](encrypted-streams.md#crypto_secretstream_xchacha20poly1305_push)
|
||||
* [crypto_secretstream_xchacha20poly1305_pull](encrypted-streams.md#crypto_secretstream_xchacha20poly1305_pull)
|
||||
* [crypto_secretstream_xchacha20poly1305_keygen](encrypted-streams.md#crypto_secretstream_xchacha20poly1305_keygen)
|
||||
* [crypto_secretstream_xchacha20poly1305_rekey](encrypted-streams.md#crypto_secretstream_xchacha20poly1305_rekey)
|
||||
* [Example for crypto_secretstream_xchacha20poly1305](encrypted-streams.md#example-for-crypto_secretstream_xchacha20poly1305)
|
||||
* [Short-input hashing](short-input-hashing.md)
|
||||
* [crypto_shorthash](short-input-hashing.md#crypto_shorthash)
|
||||
* [crypto_shorthash_keygen](short-input-hashing.md#crypto_shorthash_keygen)
|
||||
* [Example for crypto_shorthash](short-input-hashing.md#example-for-crypto_shorthash)
|
||||
* [Digital signatures](digital-signatures.md)
|
||||
* [crypto_sign](digital-signatures.md#crypto_sign)
|
||||
* [crypto_sign_open](digital-signatures.md#crypto_sign_open)
|
||||
* [crypto_sign_detached](digital-signatures.md#crypto_sign_detached)
|
||||
* [crypto_sign_verify_detached](digital-signatures.md#crypto_sign_verify_detached)
|
||||
* [crypto_sign_keypair](digital-signatures.md#crypto_sign_keypair)
|
||||
* [crypto_sign_publickey](digital-signatures.md#crypto_sign_publickey)
|
||||
* [crypto_sign_secretkey](digital-signatures.md#crypto_sign_secretkey)
|
||||
* [crypto_sign_ed25519_sk_to_curve25519](digital-signatures.md#crypto_sign_ed25519_sk_to_curve25519)
|
||||
* [crypto_sign_ed25519_pk_to_curve25519](digital-signatures.md#crypto_sign_ed25519_pk_to_curve25519)
|
||||
* [Example for crypto_sign](digital-signatures.md#example-for-crypto_sign)
|
||||
* [Randomness](randomness.md)
|
||||
* [randombytes_buf](randomness.md#randombytes_buf)
|
||||
* [randombytes_uniform](randomness.md#randombytes_uniform)
|
||||
* [Example for randombytes](randomness.md#example-for-randombytes)
|
||||
* [Utilities](utilities.md)
|
||||
* [sodium_bin2hex](utilities.md#sodium_bin2hex)
|
||||
* [sodium_hex2bin](utilities.md#sodium_bin2hex)
|
|
@ -0,0 +1,99 @@
|
|||
## Authenticated public-key encryption
|
||||
|
||||
> **See also**: [Libsodium's documentation on its public-key authenticated encryption features](https://download.libsodium.org/doc/public-key_cryptography/authenticated_encryption).
|
||||
|
||||
### crypto_box
|
||||
|
||||
Public-key authenticated encryption.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` plaintext
|
||||
2. `{Buffer}` nonce (must be 24 bytes)
|
||||
3. `{X25519SecretKey}` secret key
|
||||
4. `{X25519PublicKey}` public key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_box_open
|
||||
|
||||
Public-key authenticated encryption.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{Buffer}` ciphertext
|
||||
2. `{Buffer}` nonce (must be 24 bytes)
|
||||
3. `{X25519SecretKey}` secret key
|
||||
4. `{X25519PublicKey}` public key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
Throws a `SodiumError` on decryption failure.
|
||||
|
||||
### crypto_box_keypair
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey` containing a 64-byte
|
||||
`Buffer`. The first 32 bytes are your X25519 secret key, the latter 32 are your
|
||||
X25519 public key.
|
||||
|
||||
### crypto_box_keypair_from_secretkey_and_publickey
|
||||
|
||||
Combine two X25519 keys (secret, public) into a keypair object.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{X25519SecretKey}` secret key
|
||||
2. `{X25519PublicKey}` public key
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey`.
|
||||
|
||||
### crypto_box_publickey
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{CryptographyKey}` (buffer must be 64 bytes long)
|
||||
|
||||
Returns a `Promise` that resolves to a `X25519PublicKey`.
|
||||
|
||||
### crypto_box_secretkey
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{CryptographyKey}` (buffer must be 64 bytes long)
|
||||
|
||||
Returns a `Promise` that resolves to a `X25519SecretKey`.
|
||||
|
||||
### crypto_box_publickey_from_secretkey
|
||||
|
||||
Derive the public key from a given X25519 secret key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{X25519SecretKey}`
|
||||
|
||||
Returns a `Promise` that resolves to a `X25519PublicKey`.
|
||||
|
||||
### Example for crypto_box
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let aliceKeypair = await sodium.crypto_box_keypair();
|
||||
let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
|
||||
let bobKeypair = await sodium.crypto_box_keypair();
|
||||
let bobSecret = await sodium.crypto_box_secretkey(bobKeypair);
|
||||
let bobPublic = await sodium.crypto_box_publickey(bobKeypair);
|
||||
|
||||
let plaintext = 'Your message goes here';
|
||||
let nonce = await sodium.randombytes_buf(24);
|
||||
|
||||
let ciphertext = await sodium.crypto_box(plaintext, nonce, aliceSecret, bobPublic);
|
||||
console.log(ciphertext);
|
||||
|
||||
let decrypted = await sodium.crypto_box_open(ciphertext, nonce, bobSecret, alicePublic);
|
||||
console.log(decrypted.toString());
|
||||
})();
|
||||
```
|
134
library/sodium-plus/docs/SodiumPlus/digital-signatures.md
Normal file
134
library/sodium-plus/docs/SodiumPlus/digital-signatures.md
Normal file
|
@ -0,0 +1,134 @@
|
|||
## Digital signatures
|
||||
|
||||
> **See also**: [Libsodium's documentation on its public-key signature features](https://download.libsodium.org/doc/public-key_cryptography/public-key_signatures).
|
||||
|
||||
### crypto_sign
|
||||
|
||||
> See also: [the detached API](#crypto_sign_detached) below.
|
||||
|
||||
Sign a message with Ed25519, returning a signed message (prefixed with the signature).
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` message
|
||||
2. `{Ed25519SecretKey}` secretKey
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_sign_open
|
||||
|
||||
Verify a signed message with Ed25519, returning the original message if the signature
|
||||
is valid.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` signedMessage
|
||||
2. `{Ed25519SecretKey}` publicKey
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_sign_detached
|
||||
|
||||
Returns the Ed25519 signature of the message, for the given secret key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` message
|
||||
2. `{Ed25519SecretKey}` secretKey
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_sign_verify_detached
|
||||
|
||||
Returns true if the Ed25519 signature is valid for a given message and public key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` message
|
||||
2. `{Ed25519PublicKey}` publicKey
|
||||
3. `{Buffer}` signature
|
||||
|
||||
Returns a `Promise` that resolves to a `boolean`.
|
||||
|
||||
### crypto_sign_keypair
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey` containing a 96-byte
|
||||
`Buffer`. The first 64 bytes are your Ed25519 secret key, the latter 32 are your
|
||||
Ed25519 public key.
|
||||
|
||||
### crypto_sign_seed_keypair
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{Buffer}` 32 byte seed
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey` containing a 96-byte
|
||||
`Buffer`. The first 64 bytes are your Ed25519 secret key, the latter 32 are your
|
||||
Ed25519 public key.
|
||||
|
||||
### crypto_sign_publickey
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{CryptographyKey}` (buffer must be 96 bytes long)
|
||||
|
||||
Returns a `Promise` that resolves to a `Ed25519PublicKey`.
|
||||
|
||||
|
||||
### crypto_sign_secretkey
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{CryptographyKey}` (buffer must be 96 bytes long)
|
||||
|
||||
Returns a `Promise` that resolves to a `Ed25519SecretKey`.
|
||||
|
||||
### crypto_sign_ed25519_sk_to_curve25519
|
||||
|
||||
Obtain a birationally equivalent X25519 secret key, given an Ed25519 secret key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{Ed25519SecretKey}`
|
||||
|
||||
Returns a `Promise` that resolves to an `X25519SecretKey`.
|
||||
|
||||
### crypto_sign_ed25519_pk_to_curve25519
|
||||
|
||||
Obtain a birationally equivalent X25519 public key, given an Ed25519 public key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{Ed25519PublicKey}`
|
||||
|
||||
Returns a `Promise` that resolves to an `X25519PublicKey`.
|
||||
|
||||
### Example for crypto_sign
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let aliceKeypair = await sodium.crypto_sign_keypair();
|
||||
let aliceSecret = await sodium.crypto_sign_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_sign_publickey(aliceKeypair);
|
||||
|
||||
let message = 'This is something I need to sign publicly.';
|
||||
|
||||
// Detached mode:
|
||||
let signature = await sodium.crypto_sign_detached(message, aliceSecret);
|
||||
console.log(signature.toString('hex'));
|
||||
if (await sodium.crypto_sign_verify_detached(message, alicePublic, signature)) {
|
||||
console.log("Signature is valid.");
|
||||
} else {
|
||||
console.error("Invalid signature!");
|
||||
}
|
||||
|
||||
// NaCl (crypto_sign / crypto_sign_open):
|
||||
let signed = await sodium.crypto_sign(message, aliceSecret);
|
||||
let opened = await sodium.crypto_sign_open(signed, alicePublic);
|
||||
console.log(opened.toString());
|
||||
})();
|
||||
```
|
138
library/sodium-plus/docs/SodiumPlus/encrypted-streams.md
Normal file
138
library/sodium-plus/docs/SodiumPlus/encrypted-streams.md
Normal file
|
@ -0,0 +1,138 @@
|
|||
## Encrypted Streams
|
||||
|
||||
> **See also:** [Libsodium's documentation on its encrypted streams feature](https://download.libsodium.org/doc/secret-key_cryptography/secretstream)
|
||||
|
||||
### crypto_secretstream_xchacha20poly1305_init_push()
|
||||
|
||||
Initialize a stream for streaming encryption.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{CryptographyKey}` key
|
||||
|
||||
Returns a `Promise` that resolves to an `array` with 2 elements:
|
||||
|
||||
1. A 24-byte header that should be included in the encrypted stream.
|
||||
2. A backend-specific `state`:
|
||||
* `LibsodiumWrappers` returns a `number` (a pointer to an internal buffer)
|
||||
* `SodiumNative` returns a `CryptoSecretstreamXchacha20poly1305StateWrap`
|
||||
object
|
||||
|
||||
The `{state}` type annotation below refers to one of the backend-specific state
|
||||
types.
|
||||
|
||||
You'll typically want to use it with list unpacking syntax, like so:
|
||||
|
||||
```
|
||||
[state, header] = await sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
|
||||
```
|
||||
|
||||
### crypto_secretstream_xchacha20poly1305_init_pull()
|
||||
|
||||
Initialize a stream for streaming decryption.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{CryptographyKey}` key
|
||||
2. `{Buffer}` header (must be 24 bytes)
|
||||
|
||||
Returns a `Promise` that resolves to a backend-specific `state`:
|
||||
|
||||
* `LibsodiumWrappers` returns a `number` (a pointer to an internal buffer)
|
||||
* `SodiumNative` returns a `CryptoSecretstreamXchacha20poly1305StateWrap`
|
||||
object
|
||||
|
||||
The `{state}` type annotation below refers to one of the backend-specific state
|
||||
types.
|
||||
|
||||
### crypto_secretstream_xchacha20poly1305_push()
|
||||
|
||||
Encrypt some data in a stream.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{state}` state
|
||||
2. `{string|Buffer}` message
|
||||
3. `{string|Buffer}` (optional) additional associated data
|
||||
4. `{number}` tag (default = 0, see libsodium docs)
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer` containing the ciphertext.
|
||||
|
||||
### crypto_secretstream_xchacha20poly1305_pull()
|
||||
|
||||
Decrypt some data in a stream.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{state}` state
|
||||
2. `{string|Buffer}` ciphertext
|
||||
3. `{string|Buffer}` (optional) additional associated data
|
||||
4. `{number}` tag (default = 0, see libsodium docs)
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer` containing
|
||||
decrypted plaintext.
|
||||
|
||||
### crypto_secretstream_xchacha20poly1305_keygen()
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_secretstream` API.
|
||||
|
||||
### crypto_secretstream_xchacha20poly1305_rekey()
|
||||
|
||||
Deterministic re-keying of the internal state.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{state}` state
|
||||
|
||||
Returns a `Promise` that resolves to `undefined`. Instead,
|
||||
the `state` variable is overwritten in-place.
|
||||
|
||||
### Example for crypto_secretstream_xchacha20poly1305
|
||||
|
||||
```javascript
|
||||
const fsp = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
|
||||
let sodium;
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
let key = await sodium.crypto_secretstream_xchacha20poly1305_keygen();
|
||||
let pushState, pullState, header;
|
||||
[pushState, header] = await sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
|
||||
|
||||
// Get a test input from the text file.
|
||||
let longText = await fsp.readFile(path.join(__dirname, 'encrypted-streams.md'));
|
||||
let chunk, readUntil;
|
||||
let ciphertext = Buffer.concat([header]);
|
||||
|
||||
// How big are our chunks going to be?
|
||||
let PUSH_CHUNK_SIZE = await sodium.randombytes_uniform(longText.length - 32) + 32;
|
||||
let PULL_CHUNK_SIZE = PUSH_CHUNK_SIZE + sodium.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
|
||||
|
||||
// Encryption...
|
||||
for (let i = 0; i < longText.length; i += PUSH_CHUNK_SIZE) {
|
||||
readUntil = (i + PUSH_CHUNK_SIZE) > longText.length ? longText.length : i + PUSH_CHUNK_SIZE;
|
||||
chunk = await sodium.crypto_secretstream_xchacha20poly1305_push(
|
||||
pushState,
|
||||
longText.slice(i, readUntil)
|
||||
);
|
||||
ciphertext = Buffer.concat([ciphertext, chunk]);
|
||||
}
|
||||
|
||||
pullState = await sodium.crypto_secretstream_xchacha20poly1305_init_pull(key, header);
|
||||
// Decrypt, starting at 24 (after the header, which we already have)
|
||||
let decrypted = Buffer.alloc(0);
|
||||
for (let i = 24; i < ciphertext.length; i += PULL_CHUNK_SIZE) {
|
||||
readUntil = (i + PULL_CHUNK_SIZE) > ciphertext.length ? ciphertext.length : i + PULL_CHUNK_SIZE;
|
||||
chunk = await sodium.crypto_secretstream_xchacha20poly1305_pull(
|
||||
pullState,
|
||||
ciphertext.slice(i, readUntil)
|
||||
);
|
||||
decrypted = Buffer.concat([decrypted, chunk]);
|
||||
}
|
||||
console.log(decrypted.toString());
|
||||
})();
|
||||
```
|
|
@ -0,0 +1,82 @@
|
|||
## General-purpose cryptographic hash
|
||||
|
||||
> **See also**: [Libsodium's documentation on its generic hashing features](https://download.libsodium.org/doc/hashing/generic_hashing).
|
||||
|
||||
### crypto_generichash
|
||||
|
||||
General-purpose cryptographic hash (powered by BLAKE2).
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{Buffer}` message
|
||||
2. `{CryptographyKey|null}` key (optional)
|
||||
3. `{number}` output length (optional, defaults to 32)
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_generichash_keygen
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_generichash` API.
|
||||
|
||||
### crypto_generichash_init
|
||||
|
||||
Initialize a BLAKE2 hash context for stream hashing.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{CryptographyKey|null}` key (optional)
|
||||
2. `{number}` output length (optional, defaults to 32)
|
||||
|
||||
Returns a `Promise` that resolves to... well, that depends on your backend.
|
||||
|
||||
* sodium-native returns a `CryptoGenericHashWrap` object.
|
||||
* libsodium-wrappers returns a number (a buffer's memory address)
|
||||
|
||||
### crypto_generichash_update
|
||||
|
||||
Update the BLAKE2 hash state with a block of data.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{*}` hash state (see [crypto_generichash_init()](#crypto_generichash_init))
|
||||
2. `{string|Buffer}` message chunk
|
||||
|
||||
Returns a `Promise` that resolves to `void`. Instead, `state` is updated in-place.
|
||||
|
||||
### crypto_generichash_final
|
||||
|
||||
Obtain the final BLAKE2 hash output.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{*}` hash state (see [crypto_generichash_init()](#crypto_generichash_init))
|
||||
2. `{number}` output length (optional, defaults to 32)
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### Example for crypto_generichash
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let message = 'Any message can go here';
|
||||
let hashed = await sodium.crypto_generichash(message);
|
||||
console.log(hashed.toString('hex'));
|
||||
|
||||
let key = await sodium.crypto_generichash_keygen();
|
||||
let hash2 = await sodium.crypto_generichash(message, key, 64);
|
||||
let state = await sodium.crypto_generichash_init(key, 64);
|
||||
|
||||
await sodium.crypto_generichash_update(state, 'Any message ');
|
||||
await sodium.crypto_generichash_update(state, 'can go here');
|
||||
let hash3 = await sodium.crypto_generichash_final(state, 64);
|
||||
if (!await sodium.sodium_memcmp(hash2, hash3)) {
|
||||
throw new Error('Implementation is broken. You should never see this.');
|
||||
}
|
||||
console.log(hash2.toString('hex'));
|
||||
})();
|
||||
```
|
45
library/sodium-plus/docs/SodiumPlus/key-derivation.md
Normal file
45
library/sodium-plus/docs/SodiumPlus/key-derivation.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
## Key derivation
|
||||
|
||||
> **See also**: [Libsodium's documentation on its key derivation features](https://download.libsodium.org/doc/key_derivation).
|
||||
|
||||
### crypto_kdf_derive_from_key
|
||||
|
||||
Derive a subkey from a master key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{number}` output length (typically you want `32`)
|
||||
2. `{number}` subkey ID
|
||||
3. `{string|Buffer}` context (must be a string/buffer of length 8)
|
||||
4. `{CryptographyKey}` master key
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey`.
|
||||
|
||||
### crypto_kdf_keygen
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_kdf` API.
|
||||
|
||||
### Example for crypto_kdf
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let masterKey = await sodium.crypto_kdf_keygen();
|
||||
let context = 'Sodium++';
|
||||
|
||||
let subkey1 = await sodium.crypto_kdf_derive_from_key(32, 1, context, masterKey);
|
||||
let subkey2 = await sodium.crypto_kdf_derive_from_key(32, 2, context, masterKey);
|
||||
let subkey3 = await sodium.crypto_kdf_derive_from_key(32, 3, context, masterKey);
|
||||
|
||||
console.log({
|
||||
'master-key': masterKey.getBuffer().toString('hex'),
|
||||
'subkey1': subkey1.getBuffer().toString('hex'),
|
||||
'subkey2': subkey2.getBuffer().toString('hex'),
|
||||
'subkey3': subkey3.getBuffer().toString('hex')
|
||||
});
|
||||
})();
|
||||
```
|
94
library/sodium-plus/docs/SodiumPlus/key-exchange.md
Normal file
94
library/sodium-plus/docs/SodiumPlus/key-exchange.md
Normal file
|
@ -0,0 +1,94 @@
|
|||
## Key exchange
|
||||
|
||||
> **See also**: [Libsodium's documentation on its key exchange features](https://download.libsodium.org/doc/key_exchange).
|
||||
|
||||
### crypto_kx_keypair
|
||||
|
||||
This is functionally identical to [`crypto_box_keypair()`](#crypto_box_keypair).
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey` with 64 bytes.
|
||||
|
||||
### crypto_kx_seed_keypair
|
||||
|
||||
Generate an X25519 keypair from a seed. Unlike `crypto_kx_seedpair()`, this is
|
||||
deterministic from your seed.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` seed
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey` with 64 bytes.
|
||||
|
||||
### crypto_kx_client_session_keys
|
||||
|
||||
Perform a key exchange from the client's perspective.
|
||||
|
||||
Returns an array of two CryptographyKey objects:
|
||||
|
||||
* The first is meant for data sent from the server to the client (incoming decryption).
|
||||
* The second is meant for data sent from the client to the server (outgoing encryption).
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{X25519PublicKey}` client public key (yours)
|
||||
2. `{X25519SecretKey}` client secret key (yours)
|
||||
1. `{X25519PublicKey}` server public key (theirs)
|
||||
|
||||
Returns a `Promise` that resolves to an array of two `CryptographyKey` objects.
|
||||
|
||||
### crypto_kx_server_session_keys
|
||||
|
||||
Perform a key exchange from the server's perspective.
|
||||
|
||||
Returns an array of two CryptographyKey objects:
|
||||
|
||||
* The first is meant for data sent from the client to the server (incoming decryption).
|
||||
* The second is meant for data sent from the server to the client (outgoing encryption).
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{X25519PublicKey}` server public key (yours)
|
||||
2. `{X25519SecretKey}` server secret key (yours)
|
||||
1. `{X25519PublicKey}` client public key (theirs)
|
||||
|
||||
Returns a `Promise` that resolves to an array of two `CryptographyKey` objects.
|
||||
|
||||
### Example for crypto_kx
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let clientKeypair = await sodium.crypto_box_keypair();
|
||||
let clientSecret = await sodium.crypto_box_secretkey(clientKeypair);
|
||||
let clientPublic = await sodium.crypto_box_publickey(clientKeypair);
|
||||
let serverKeypair = await sodium.crypto_kx_seed_keypair('Your static input goes here');
|
||||
let serverSecret = await sodium.crypto_box_secretkey(serverKeypair);
|
||||
let serverPublic = await sodium.crypto_box_publickey(serverKeypair);
|
||||
let clientIKey, clientOKey, serverIKey, serverOKey;
|
||||
|
||||
[clientIKey, clientOKey] = await sodium.crypto_kx_client_session_keys(
|
||||
clientPublic,
|
||||
clientSecret,
|
||||
serverPublic
|
||||
);
|
||||
[serverIKey, serverOKey] = await sodium.crypto_kx_server_session_keys(
|
||||
serverPublic,
|
||||
serverSecret,
|
||||
clientPublic
|
||||
);
|
||||
|
||||
console.log({
|
||||
'client-sees': {
|
||||
'incoming': clientIKey.getBuffer().toString('hex'),
|
||||
'outgoing': clientOKey.getBuffer().toString('hex')
|
||||
},
|
||||
'server-sees': {
|
||||
'incoming': serverIKey.getBuffer().toString('hex'),
|
||||
'outgoing': serverOKey.getBuffer().toString('hex')
|
||||
}
|
||||
});
|
||||
})();
|
||||
```
|
|
@ -0,0 +1,52 @@
|
|||
## One-time authentication
|
||||
|
||||
> **See also**: [Libsodium's documentation on its one-time authentication features](https://download.libsodium.org/doc/advanced/poly1305).
|
||||
|
||||
### crypto_onetimeauth
|
||||
|
||||
Get an authenticator for a message for a given key.
|
||||
|
||||
**Important:** In order to be secure, keys must be:
|
||||
|
||||
1. Secret.
|
||||
2. Unpredictable.
|
||||
3. Unique.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` message
|
||||
2. `{CryptographyKey}` key
|
||||
|
||||
Return a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_onetimeauth_verify
|
||||
|
||||
Verify an authenticator for a message for a given key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` message
|
||||
2. `{CryptographyKey}` key
|
||||
2. `{Buffer}` tag
|
||||
|
||||
Return a `Promise` that resolves to a `boolean`.
|
||||
|
||||
### crypto_onetimeauth_keygen
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_auth` API.
|
||||
|
||||
### Example for crypto_onetimeauth
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = 'Your message goes here';
|
||||
let key = await sodium.crypto_onetimeauth_keygen();
|
||||
let tag = await sodium.crypto_onetimeauth(plaintext, key);
|
||||
console.log(await sodium.crypto_onetimeauth_verify(plaintext, key, tag));
|
||||
})();
|
||||
```
|
|
@ -0,0 +1,45 @@
|
|||
## Password-based key derivation
|
||||
|
||||
> **See also**: [Libsodium's documentation on Argon2](https://download.libsodium.org/doc/password_hashing/the_argon2i_function).
|
||||
|
||||
### crypto_pwhash
|
||||
|
||||
Derive a cryptography key from a password and salt.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{number}` output length
|
||||
2. `{string|Buffer}` password
|
||||
3. `{Buffer}` salt (16 bytes)
|
||||
4. `{number}` opslimit (recommeded minimum: `2`)
|
||||
5. `{number}` memlimit (recommended mimimum: `67108864` a.k.a. 64MiB)
|
||||
6. `{number|null}` algorithm (recommended: `this.CRYPTO_PWHASH_ALG_DEFAULT`)
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey`.
|
||||
|
||||
### Example for crypto_pwhash
|
||||
|
||||
This example is for key derivation. Look [below](#example-for-crypto_pwhash_str)
|
||||
for information about password storage/verification.
|
||||
|
||||
```javascript
|
||||
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
let password = 'correct horse battery staple';
|
||||
let salt = await sodium.randombytes_buf(16);
|
||||
|
||||
let key = await sodium.crypto_pwhash(
|
||||
32,
|
||||
password,
|
||||
salt,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
|
||||
);
|
||||
console.log(key.getBuffer().toString('hex'));
|
||||
})();
|
||||
```
|
|
@ -0,0 +1,74 @@
|
|||
## Password hashing and storage
|
||||
|
||||
> **See also**: [Libsodium's documentation on its password hashing features](https://download.libsodium.org/doc/password_hashing).
|
||||
|
||||
### crypto_pwhash_str
|
||||
|
||||
Get a password hash (in a safe-for-storage format).
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` password
|
||||
2. `{number}` opslimit (recommeded minimum: `2`)
|
||||
3. `{number}` memlimit (recommended mimimum: `67108864` a.k.a. 64MiB)
|
||||
|
||||
Returns a `Promise` that resolves to a `string`.
|
||||
|
||||
### crypto_pwhash_str_needs_rehash
|
||||
|
||||
Does this password need to be rehashed? (i.e. have the algorithm parameters
|
||||
we want changed since the hash was generated?)
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string}` password hash
|
||||
2. `{number}` opslimit (recommeded minimum: `2`)
|
||||
3. `{number}` memlimit (recommended mimimum: `67108864` a.k.a. 64MiB)
|
||||
|
||||
Returns a `Promise` that resolves to a `boolean`.
|
||||
|
||||
### crypto_pwhash_str_verify
|
||||
|
||||
Verify a password against a known password hash.
|
||||
|
||||
1. `{string|Buffer}` password
|
||||
2. `{string}` password hash
|
||||
|
||||
Returns a `Promise` that resolves to a `boolean`.
|
||||
|
||||
### Example for crypto_pwhash_str
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let password = 'correct horse battery staple';
|
||||
|
||||
// Generating a password hash
|
||||
let pwhash = await sodium.crypto_pwhash_str(
|
||||
password,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
|
||||
);
|
||||
console.log(pwhash);
|
||||
|
||||
// Check that we don't need to rotate hashes
|
||||
let stale = await sodium.crypto_pwhash_str_needs_rehash(
|
||||
pwhash,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
|
||||
);
|
||||
if (stale) {
|
||||
console.warn('Password needs to be rehashed');
|
||||
}
|
||||
|
||||
// Password validation
|
||||
if (await sodium.crypto_pwhash_str_verify(password, pwhash)) {
|
||||
console.log("Password valid");
|
||||
} else {
|
||||
console.error("Incorrect password");
|
||||
}
|
||||
})();
|
||||
```
|
43
library/sodium-plus/docs/SodiumPlus/randomness.md
Normal file
43
library/sodium-plus/docs/SodiumPlus/randomness.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
## Randomness
|
||||
|
||||
> **See also:** [Libsodium's documentation on its random data features](https://download.libsodium.org/doc/generating_random_data).
|
||||
|
||||
### randombytes_buf
|
||||
|
||||
Obtain a buffer filled with random bytes.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{number}` Size of buffer to return
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`
|
||||
|
||||
### randombytes_uniform
|
||||
|
||||
Generate an integer between 0 and upperBound (non-inclusive).
|
||||
|
||||
For example, randombytes_uniform(10) returns an integer between 0 and 9.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{number}` Upper bound
|
||||
|
||||
Returns a `Promise` that resolves to a `number`.
|
||||
|
||||
### Example for randombytes
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
let someBuf = await sodium.randombytes_buf(32);
|
||||
console.log(someBuf.toString('hex'));
|
||||
|
||||
let someInt = await sodium.randombytes_uniform(65536);
|
||||
console.log(someInt);
|
||||
})();
|
||||
```
|
49
library/sodium-plus/docs/SodiumPlus/scalar-multiplication.md
Normal file
49
library/sodium-plus/docs/SodiumPlus/scalar-multiplication.md
Normal file
|
@ -0,0 +1,49 @@
|
|||
## Scalar multiplication over Curve25519
|
||||
|
||||
> **See also**: [Libsodium's documentation on its scalar multiplication features](https://download.libsodium.org/doc/advanced/scalar_multiplication).
|
||||
|
||||
### crypto_scalarmult
|
||||
|
||||
Elliptic Curve Diffie-Hellman key exchange over Curve25519.
|
||||
You probably don't want to ever use this directly.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{X25519SecretKey}` your secret key
|
||||
2. `{X25519PublicKey}` their public key
|
||||
|
||||
Returns a `Promise` that resolves to a `CryptographyKey`.
|
||||
|
||||
### crypto_scalarmult_base
|
||||
|
||||
Generate an X25519PublicKey from an X25519SecretKey.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{X25519SecretKey}` your secret key
|
||||
|
||||
Returns a `Promise` that resolves to an `X25519PublicKey`.
|
||||
|
||||
### Example for crypto_scalarmult
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let aliceKeypair = await sodium.crypto_box_keypair();
|
||||
let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
|
||||
let bobKeypair = await sodium.crypto_box_keypair();
|
||||
let bobSecret = await sodium.crypto_box_secretkey(bobKeypair);
|
||||
let bobPublic = await sodium.crypto_scalarmult_base(bobSecret);
|
||||
|
||||
let aliceToBob = await sodium.crypto_scalarmult(aliceSecret, bobPublic);
|
||||
let bobToAlice = await sodium.crypto_scalarmult(bobSecret, alicePublic);
|
||||
console.log({
|
||||
'alice-to-bob': aliceToBob.getBuffer().toString('hex'),
|
||||
'bob-to-alice': bobToAlice.getBuffer().toString('hex')
|
||||
});
|
||||
})();
|
||||
```
|
48
library/sodium-plus/docs/SodiumPlus/sealed-boxes.md
Normal file
48
library/sodium-plus/docs/SodiumPlus/sealed-boxes.md
Normal file
|
@ -0,0 +1,48 @@
|
|||
## Sealed boxes
|
||||
|
||||
> **See also**: [Libsodium's documentation on its sealed boxes features](https://download.libsodium.org/doc/public-key_cryptography/sealed_boxes).
|
||||
|
||||
### crypto_box_seal
|
||||
|
||||
Anonymous public-key encryption. (Message integrity is still assured.)
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` plaintext
|
||||
2. `{X25519PublicKey}` public key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_box_seal_open
|
||||
|
||||
Anonymous public-key decryption. (Message integrity is still assured.)
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{Buffer}` ciphertext
|
||||
2. `{X25519PublicKey}` public key
|
||||
3. `{X25519SecretKey}` secret key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### Example for crypto_box_seal
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let aliceKeypair = await sodium.crypto_box_keypair();
|
||||
let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
|
||||
|
||||
let plaintext = 'Your message goes here';
|
||||
|
||||
let ciphertext = await sodium.crypto_box_seal(plaintext, alicePublic);
|
||||
console.log(ciphertext);
|
||||
|
||||
let decrypted = await sodium.crypto_box_seal_open(ciphertext, alicePublic, aliceSecret);
|
||||
console.log(decrypted.toString());
|
||||
})();
|
||||
```
|
|
@ -0,0 +1,62 @@
|
|||
## Shared-key authenticated encryption
|
||||
|
||||
> **See also**: [Libsodium's documentation on its shared-key authenticated encryption features](https://download.libsodium.org/doc/secret-key_cryptography/secretbox).
|
||||
|
||||
### crypto_secretbox
|
||||
|
||||
Shared-key authenticated encryption.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` Plaintext
|
||||
2. `{string|Buffer}` nonce (must be 24 bytes)
|
||||
3. `{CryptographyKey}` key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_secretbox_open
|
||||
|
||||
Shared-key authenticated decryption.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` Ciphertext
|
||||
2. `{string|Buffer}` nonce (must be 24 bytes)
|
||||
3. `{CryptographyKey}` key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
Throws a `SodiumError` on decryption failure.
|
||||
|
||||
### crypto_secretbox_keygen
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_secretbox` API.
|
||||
|
||||
### Example for crypto_secretbox
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = 'Your message goes here';
|
||||
let key = await sodium.crypto_secretbox_keygen();
|
||||
let nonce = await sodium.randombytes_buf(24);
|
||||
let ciphertext = await sodium.crypto_secretbox(
|
||||
plaintext,
|
||||
nonce,
|
||||
key
|
||||
);
|
||||
|
||||
console.log(ciphertext.toString('hex'));
|
||||
|
||||
let decrypted = await sodium.crypto_secretbox_open(
|
||||
ciphertext,
|
||||
nonce,
|
||||
key
|
||||
);
|
||||
|
||||
console.log(decrypted.toString());
|
||||
})();
|
||||
```
|
|
@ -0,0 +1,46 @@
|
|||
## Shared-key authentication
|
||||
|
||||
> **See also**: [Libsodium's documentation on its shared-key authentication features](https://download.libsodium.org/doc/secret-key_cryptography/secret-key_authentication).
|
||||
|
||||
### crypto_auth
|
||||
|
||||
Get an authenticator for a message for a given key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` message
|
||||
2. `{CryptographyKey}` key
|
||||
|
||||
Return a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_auth_verify
|
||||
|
||||
Verify an authenticator for a message for a given key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` message
|
||||
2. `{CryptographyKey}` key
|
||||
2. `{Buffer}` mac
|
||||
|
||||
Return a `Promise` that resolves to a `boolean`.
|
||||
|
||||
### crypto_auth_keygen
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_auth` API.
|
||||
|
||||
### Example for crypto_auth
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = 'Your message goes here';
|
||||
let key = await sodium.crypto_auth_keygen();
|
||||
let mac = await sodium.crypto_auth(plaintext, key);
|
||||
console.log(await sodium.crypto_auth_verify(plaintext, key, mac));
|
||||
})();
|
||||
```
|
39
library/sodium-plus/docs/SodiumPlus/short-input-hashing.md
Normal file
39
library/sodium-plus/docs/SodiumPlus/short-input-hashing.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
## Short-input hashing
|
||||
|
||||
> **See also**: [Libsodium's documentation on its short-input hashing features](https://download.libsodium.org/doc/hashing/short-input_hashing).
|
||||
|
||||
### crypto_shorthash
|
||||
|
||||
Calculate a fast hash for short inputs.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` input
|
||||
3. `{CryptographyKey}` key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
### crypto_shorthash_keygen
|
||||
|
||||
Returns a `CryptographyKey` object containing a key appropriate
|
||||
for the `crypto_shorthash` API.
|
||||
|
||||
### Example for crypto_shorthash
|
||||
|
||||
> **Warning:** You probably want [`crypto_generichash()`](general-purpose-cryptographic-hash.md)
|
||||
> for most use-cases. `crypto_shorthash()` does not offer collision resistance.
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let key = await sodium.crypto_shorthash_keygen();
|
||||
let mapped = {};
|
||||
mapped['foo'] = (await sodium.crypto_shorthash('foo', key)).toString('hex');
|
||||
mapped['bar'] = (await sodium.crypto_shorthash('bar', key)).toString('hex');
|
||||
mapped['baz'] = (await sodium.crypto_shorthash('baz', key)).toString('hex');
|
||||
console.log(mapped);
|
||||
})();
|
||||
```
|
55
library/sodium-plus/docs/SodiumPlus/stream-ciphers.md
Normal file
55
library/sodium-plus/docs/SodiumPlus/stream-ciphers.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
## Stream Ciphers
|
||||
|
||||
> **See also**: [Libsodium's documentation on its stream cipher features](https://download.libsodium.org/doc/advanced/stream_ciphers/xsalsa20).
|
||||
|
||||
### crypto_stream
|
||||
|
||||
Obtain an arbitrary-length stream of pseudorandom bytes from a given
|
||||
nonce and key.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{number}` length
|
||||
2. `{Buffer}` nonce (must be 24 bytes)
|
||||
3. `{CryptographyKey}` key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer` containing
|
||||
the pseudorandom bytes.
|
||||
|
||||
### crypto_stream_xor
|
||||
|
||||
Encrypt a message with a given nonce and key.
|
||||
|
||||
> [**Danger: Unauthenticated encryption!**](https://tonyarcieri.com/all-the-crypto-code-youve-ever-written-is-probably-broken)
|
||||
> Without a subsequent message authentication strategy, this is vulnerable to
|
||||
> chosen-ciphertext attacks. Proceed with caution!
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` plaintext
|
||||
2. `{Buffer}` nonce (must be 24 bytes)
|
||||
3. `{CryptographyKey}` key
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer` containing
|
||||
the encrypted bytes.
|
||||
|
||||
### Example for crypto_stream
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
|
||||
let sodium;
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let key = await sodium.crypto_stream_keygen();
|
||||
let iv = await sodium.randombytes_buf(24);
|
||||
let output = await sodium.crypto_stream(64, iv, key);
|
||||
console.log(output);
|
||||
|
||||
iv = await sodium.randombytes_buf(24);
|
||||
let plaintext = 'This is a secret message';
|
||||
let ciphertext = await sodium.crypto_stream_xor(plaintext, iv, key);
|
||||
let decrypted = await sodium.crypto_stream_xor(ciphertext, iv, key);
|
||||
console.log(decrypted.toString());
|
||||
})();
|
||||
```
|
45
library/sodium-plus/docs/SodiumPlus/utilities.md
Normal file
45
library/sodium-plus/docs/SodiumPlus/utilities.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
## Utilities
|
||||
|
||||
### sodium_bin2hex
|
||||
|
||||
Encode data into a hexadecimal string.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` non-hex-encoded input
|
||||
|
||||
Returns a `Promise` that resolves to a `string`.
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let buf = await sodium.randombytes_buf(32);
|
||||
|
||||
console.log(await sodium.sodium_bin2hex(buf));
|
||||
})();
|
||||
```
|
||||
|
||||
### sodium_hex2bin
|
||||
|
||||
Decode data from a hexadecimal string to a `Buffer`.
|
||||
|
||||
**Parameters and their respective types**:
|
||||
|
||||
1. `{string|Buffer}` hex-encoded input
|
||||
|
||||
Returns a `Promise` that resolves to a `Buffer`.
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let hex = '491d40c4924ba547d6f0bda9da77a539391decdc';
|
||||
|
||||
console.log(await sodium.sodium_hex2bin(hex));
|
||||
})();
|
||||
```
|
100
library/sodium-plus/docs/getting-started.md
Normal file
100
library/sodium-plus/docs/getting-started.md
Normal file
|
@ -0,0 +1,100 @@
|
|||
# Getting Started
|
||||
|
||||
You always want to use `SodiumPlus` from within an asynchronous function.
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
async function myFunction() {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
// Now you can use sodium.FUNCTION_NAME_HERE()
|
||||
}
|
||||
```
|
||||
|
||||
When you use `await SodiumPlus.auto()`, this will automatically load in the best
|
||||
backend available for your platform. This is the recommended way to use SodiumPlus.
|
||||
|
||||
If you'd rather use a specific backend, you can do the following:
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus, SodiumUtil, getBackendObject } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
async function myFunction() {
|
||||
if (!sodium) {
|
||||
let backend = getBackendObject('LibsodiumWrappers');
|
||||
SodiumUtil.populateConstants(backend);
|
||||
sodium = new SodiumPlus(backend);
|
||||
}
|
||||
|
||||
// Now you can use sodium.FUNCTION_NAME_HERE()
|
||||
}
|
||||
```
|
||||
|
||||
To discover what backend you're using at runtime, invoke the `getBackendName()`
|
||||
method on the `SodiumPlus` object, like so:
|
||||
|
||||
|
||||
```javascript
|
||||
const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
async function whichBackend() {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
console.log(sodium.getBackendName());
|
||||
}
|
||||
```
|
||||
|
||||
## CryptographyKey
|
||||
|
||||
All cryptographic secrets are contained within a `CryptographyKey` object
|
||||
(or one of its derived classes). You can create and access them like so:
|
||||
|
||||
```javascript
|
||||
const { CryptographyKey } = require('sodium-plus');
|
||||
let buf = Buffer.alloc(32);
|
||||
let key = new CryptographyKey(buf);
|
||||
|
||||
// If you do this, the internal buffer will not be visible!
|
||||
console.log(key);
|
||||
// CryptographyKey {}
|
||||
|
||||
// You'll need to do this instead:
|
||||
console.log(key.getBuffer());
|
||||
// <Buffer d9 ff 60 6b ff 96 f6 26 05 53 07 39 ef b5 a5 8b 26 0c 72 9e 1b b7 e4 97 fe 09 de 07 86 8a 0c b6>
|
||||
```
|
||||
|
||||
The following classes inherit from `CryptographyKey`:
|
||||
|
||||
* `Ed25519PublicKey` -- Ed25519 public key
|
||||
* `Ed25519SecretKey` -- Ed25519 secret key
|
||||
* `X25519PublicKey` -- X25519 public key
|
||||
* `X25519SecretKey` -- X25519 secret key
|
||||
|
||||
## Sodium-Plus in the Browser
|
||||
|
||||
First, download [sodium-plus.min.js](../dist) (or find it on a CDN you trust).
|
||||
|
||||
Next, include the following script tags in your web page:
|
||||
|
||||
```html5
|
||||
<script src="sodium-plus.min.js"></script>
|
||||
<script>
|
||||
(async function() {
|
||||
if (!window.sodium) window.sodium = await SodiumPlus.auto();
|
||||
|
||||
// You can now use the sodium object here.
|
||||
|
||||
// Just some example code to ensure it's running:
|
||||
let random = await sodium.randombytes_buf(32);
|
||||
let hash = await sodium.crypto_generichash('hello world');
|
||||
console.log({
|
||||
'random': random.toString('hex'),
|
||||
'hash': hash.toString('hex')
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
You can then use the `sodium` API as documented.
|
433
library/sodium-plus/index.d.ts
vendored
Normal file
433
library/sodium-plus/index.d.ts
vendored
Normal file
|
@ -0,0 +1,433 @@
|
|||
/// <reference types="node" />
|
||||
|
||||
// Helper for defining opaque types like crypto_secretstream_xchacha20poly1305_state.
|
||||
declare const brand: unique symbol;
|
||||
interface Opaque<T> {
|
||||
readonly [brand]: T;
|
||||
}
|
||||
|
||||
// Separate the tag constants that crypto_secretstream_xchacha20poly1305_* functions
|
||||
// take so that we can use them to limit the input values for those functions.
|
||||
interface CryptoSecretStreamTagConstants {
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH: 0;
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL: 1;
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY: 2;
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL: 3;
|
||||
}
|
||||
type CryptoSecretStreamTagValues = CryptoSecretStreamTagConstants[keyof CryptoSecretStreamTagConstants];
|
||||
|
||||
interface Constants extends CryptoSecretStreamTagConstants {
|
||||
LIBRARY_VERSION_MAJOR: number;
|
||||
LIBRARY_VERSION_MINOR: number;
|
||||
VERSION_STRING: string;
|
||||
BASE64_VARIANT_ORIGINAL: number;
|
||||
BASE64_VARIANT_ORIGINAL_NO_PADDING: number;
|
||||
BASE64_VARIANT_URLSAFE: number;
|
||||
BASE64_VARIANT_URLSAFE_NO_PADDING: number;
|
||||
CRYPTO_AEAD_AES256GCM_KEYBYTES: number;
|
||||
CRYPTO_AEAD_AES256GCM_NSECBYTES: number;
|
||||
CRYPTO_AEAD_AES256GCM_NPUBBYTES: number;
|
||||
CRYPTO_AEAD_AES256GCM_ABYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_ABYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES: number;
|
||||
CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES: number;
|
||||
CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES: number;
|
||||
CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES: number;
|
||||
CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES: number;
|
||||
CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES: number;
|
||||
CRYPTO_AUTH_BYTES: number;
|
||||
CRYPTO_AUTH_KEYBYTES: number;
|
||||
CRYPTO_BOX_SEALBYTES: number;
|
||||
CRYPTO_BOX_SECRETKEYBYTES: number;
|
||||
CRYPTO_BOX_PUBLICKEYBYTES: number;
|
||||
CRYPTO_BOX_KEYPAIRBYTES: number;
|
||||
CRYPTO_BOX_MACBYTES: number;
|
||||
CRYPTO_BOX_NONCEBYTES: number;
|
||||
CRYPTO_BOX_SEEDBYTES: number;
|
||||
CRYPTO_KDF_BYTES_MIN: number;
|
||||
CRYPTO_KDF_BYTES_MAX: number;
|
||||
CRYPTO_KDF_CONTEXTBYTES: number;
|
||||
CRYPTO_KDF_KEYBYTES: number;
|
||||
CRYPTO_KX_BYTES: number;
|
||||
CRYPTO_KX_PRIMITIVE: string;
|
||||
CRYPTO_KX_SEEDBYTES: number;
|
||||
CRYPTO_KX_KEYPAIRBYTES: number;
|
||||
CRYPTO_KX_PUBLICKEYBYTES: number;
|
||||
CRYPTO_KX_SECRETKEYBYTES: number;
|
||||
CRYPTO_KX_SESSIONKEYBYTES: number;
|
||||
CRYPTO_GENERICHASH_BYTES: number;
|
||||
CRYPTO_GENERICHASH_BYTES_MIN: number;
|
||||
CRYPTO_GENERICHASH_BYTES_MAX: number;
|
||||
CRYPTO_GENERICHASH_KEYBYTES: number;
|
||||
CRYPTO_GENERICHASH_KEYBYTES_MIN: number;
|
||||
CRYPTO_GENERICHASH_KEYBYTES_MAX: number;
|
||||
CRYPTO_PWHASH_SALTBYTES: number;
|
||||
CRYPTO_PWHASH_STRPREFIX: string;
|
||||
CRYPTO_PWHASH_ALG_ARGON2I13: number;
|
||||
CRYPTO_PWHASH_ALG_ARGON2ID13: number;
|
||||
CRYPTO_PWHASH_ALG_DEFAULT: number;
|
||||
CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE: number;
|
||||
CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE: number;
|
||||
CRYPTO_PWHASH_OPSLIMIT_MODERATE: number;
|
||||
CRYPTO_PWHASH_MEMLIMIT_MODERATE: number;
|
||||
CRYPTO_PWHASH_OPSLIMIT_SENSITIVE: number;
|
||||
CRYPTO_PWHASH_MEMLIMIT_SENSITIVE: number;
|
||||
CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES: number;
|
||||
CRYPTO_SCALARMULT_BYTES: number;
|
||||
CRYPTO_SCALARMULT_SCALARBYTES: number;
|
||||
CRYPTO_SHORTHASH_BYTES: number;
|
||||
CRYPTO_SHORTHASH_KEYBYTES: number;
|
||||
CRYPTO_SECRETBOX_KEYBYTES: number;
|
||||
CRYPTO_SECRETBOX_MACBYTES: number;
|
||||
CRYPTO_SECRETBOX_NONCEBYTES: number;
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES: number;
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES: number;
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES: number;
|
||||
CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX: number;
|
||||
CRYPTO_SIGN_BYTES: number;
|
||||
CRYPTO_SIGN_SEEDBYTES: number;
|
||||
CRYPTO_SIGN_PUBLICKEYBYTES: number;
|
||||
CRYPTO_SIGN_SECRETKEYBYTES: number;
|
||||
CRYPTO_SIGN_KEYPAIRBYTES: number;
|
||||
CRYPTO_STREAM_KEYBYTES: number;
|
||||
CRYPTO_STREAM_NONCEBYTES: number;
|
||||
}
|
||||
|
||||
declare namespace Module {
|
||||
export type crypto_secretstream_xchacha20poly1305_state = Opaque<
|
||||
"crypto_secretstream_xchacha20poly1305_state"
|
||||
>;
|
||||
export type crypto_generichash_state = Opaque<"crypto_generichash_state">;
|
||||
export type Backend = Opaque<"Backend">;
|
||||
|
||||
export class CryptographyKey {
|
||||
// Deny types that would otherwise structurally match CryptographyKey.
|
||||
// See: https://michalzalecki.com/nominal-typing-in-typescript/
|
||||
private readonly __nominal: void;
|
||||
|
||||
constructor(buf: Buffer);
|
||||
static from(...args: Parameters<typeof Buffer.from>): CryptographyKey;
|
||||
isEd25519Key(): boolean;
|
||||
isX25519Key(): boolean;
|
||||
isPublicKey(): boolean;
|
||||
getLength(): number;
|
||||
getBuffer(): Buffer;
|
||||
toString(encoding?: string): string;
|
||||
slice(): Buffer;
|
||||
}
|
||||
export class Ed25519PublicKey extends CryptographyKey {
|
||||
readonly keyType: "ed25519";
|
||||
readonly publicKey: true;
|
||||
static from(...args: Parameters<typeof Buffer.from>): Ed25519PublicKey;
|
||||
}
|
||||
export class Ed25519SecretKey extends CryptographyKey {
|
||||
readonly keyType: "ed25519";
|
||||
readonly publicKey: false;
|
||||
static from(...args: Parameters<typeof Buffer.from>): Ed25519SecretKey;
|
||||
}
|
||||
export class X25519PublicKey extends CryptographyKey {
|
||||
readonly keyType: "x25519";
|
||||
readonly publicKey: true;
|
||||
static from(...args: Parameters<typeof Buffer.from>): X25519PublicKey;
|
||||
}
|
||||
export class X25519SecretKey extends CryptographyKey {
|
||||
readonly keyType: "x25519";
|
||||
readonly publicKey: false;
|
||||
static from(...args: Parameters<typeof Buffer.from>): X25519SecretKey;
|
||||
}
|
||||
|
||||
export class SodiumError extends Error {}
|
||||
|
||||
export function getBackendObject(
|
||||
type?: "SodiumNative" | "LibsodiumWrappers"
|
||||
): Backend;
|
||||
|
||||
// Mix in Constants.* to SodiumPlus instances.
|
||||
export interface SodiumPlus extends Constants {}
|
||||
export class SodiumPlus {
|
||||
readonly backend: Backend;
|
||||
|
||||
constructor(backend: Backend);
|
||||
|
||||
getBackendName(): string;
|
||||
isSodiumNative(): boolean;
|
||||
isLibsodiumWrappers(): boolean;
|
||||
|
||||
static auto(): Promise<SodiumPlus>;
|
||||
ensureLoaded(): Promise<void>;
|
||||
|
||||
crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
ciphertext: string | Buffer,
|
||||
nonce: string | Buffer,
|
||||
key: CryptographyKey,
|
||||
assocData?: string | Buffer
|
||||
): Promise<Buffer>;
|
||||
crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
plaintext: string | Buffer,
|
||||
nonce: string | Buffer,
|
||||
key: CryptographyKey,
|
||||
assocData?: string | Buffer
|
||||
): Promise<Buffer>;
|
||||
crypto_aead_xchacha20poly1305_ietf_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_auth(
|
||||
message: string | Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
crypto_auth_keygen(): Promise<CryptographyKey>;
|
||||
crypto_auth_verify(
|
||||
message: string | Buffer,
|
||||
key: CryptographyKey,
|
||||
mac: Buffer
|
||||
): Promise<boolean>;
|
||||
crypto_box(
|
||||
plaintext: string | Buffer,
|
||||
nonce: Buffer,
|
||||
myPrivateKey: X25519SecretKey,
|
||||
theirPublicKey: X25519PublicKey
|
||||
): Promise<Buffer>;
|
||||
crypto_box_open(
|
||||
ciphertext: Buffer,
|
||||
nonce: Buffer,
|
||||
myPrivateKey: X25519SecretKey,
|
||||
theirPublicKey: X25519PublicKey
|
||||
): Promise<Buffer>;
|
||||
|
||||
crypto_box_keypair(): Promise<CryptographyKey>;
|
||||
crypto_box_keypair_from_secretkey_and_secretkey(
|
||||
sKey: X25519SecretKey,
|
||||
pKey: X25519PublicKey
|
||||
): Promise<CryptographyKey>;
|
||||
crypto_box_secretkey(keypair: CryptographyKey): Promise<X25519SecretKey>;
|
||||
crypto_box_publickey(keypair: CryptographyKey): Promise<X25519PublicKey>;
|
||||
crypto_box_publickey_from_secretkey(
|
||||
secretKey: X25519SecretKey
|
||||
): Promise<X25519PublicKey>;
|
||||
crypto_box_seal(
|
||||
plaintext: string | Buffer,
|
||||
publicKey: X25519PublicKey
|
||||
): Promise<Buffer>;
|
||||
crypto_box_seal_open(
|
||||
ciphertext: Buffer,
|
||||
publicKey: X25519PublicKey,
|
||||
secretKey: X25519SecretKey
|
||||
): Promise<Buffer>;
|
||||
|
||||
crypto_generichash(
|
||||
message: string | Buffer,
|
||||
key?: CryptographyKey | null,
|
||||
outputLength?: number
|
||||
): Promise<Buffer>;
|
||||
|
||||
crypto_generichash_init(
|
||||
key?: CryptographyKey | null,
|
||||
outputLength?: number
|
||||
): Promise<crypto_generichash_state>;
|
||||
crypto_generichash_update(
|
||||
state: crypto_generichash_state,
|
||||
message: string | Buffer
|
||||
): Promise<crypto_generichash_state>;
|
||||
crypto_generichash_final(
|
||||
state: crypto_generichash_state,
|
||||
outputLength?: number
|
||||
): Promise<Buffer>;
|
||||
crypto_generichash_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_kdf_derive_from_key(
|
||||
length: number,
|
||||
subKeyId: number,
|
||||
context: string | Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<CryptographyKey>;
|
||||
crypto_kdf_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_kx_keypair(): Promise<CryptographyKey>;
|
||||
crypto_kx_seed_keypair(seed: string | Buffer): Promise<CryptographyKey>;
|
||||
crypto_kx_client_session_keys(
|
||||
clientPublicKey: X25519PublicKey,
|
||||
clientSecretKey: X25519SecretKey,
|
||||
serverPublicKey: X25519PublicKey
|
||||
): Promise<CryptographyKey[]>;
|
||||
crypto_kx_server_session_keys(
|
||||
serverPublicKey: X25519PublicKey,
|
||||
serverSecretKey: X25519SecretKey,
|
||||
clientPublicKey: X25519PublicKey
|
||||
): Promise<CryptographyKey[]>;
|
||||
|
||||
crypto_onetimeauth(
|
||||
message: string | Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
crypto_onetimeauth_verify(
|
||||
message: string | Buffer,
|
||||
key: CryptographyKey,
|
||||
tag: Buffer
|
||||
): Promise<boolean>;
|
||||
crypto_onetimeauth_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_pwhash(
|
||||
length: number,
|
||||
password: string | Buffer,
|
||||
salt: Buffer,
|
||||
opslimit: number,
|
||||
memlimit: number,
|
||||
algorithm?: number | null
|
||||
): Promise<CryptographyKey>;
|
||||
crypto_pwhash_str(
|
||||
password: string | Buffer,
|
||||
opslimit: number,
|
||||
memlimit: number
|
||||
): Promise<string>;
|
||||
crypto_pwhash_str_verify(
|
||||
password: string | Buffer,
|
||||
hash: string | Buffer
|
||||
): Promise<boolean>;
|
||||
crypto_pwhash_str_needs_rehash(
|
||||
hash: string | Buffer,
|
||||
opslimit: number,
|
||||
memlimit: number
|
||||
): Promise<boolean>;
|
||||
|
||||
crypto_scalarmult(
|
||||
secretKey: X25519SecretKey,
|
||||
publicKey: X25519PublicKey
|
||||
): Promise<CryptographyKey>;
|
||||
crypto_scalarmult_base(
|
||||
secretKey: X25519SecretKey
|
||||
): Promise<X25519PublicKey>;
|
||||
|
||||
crypto_secretbox(
|
||||
plaintext: string | Buffer,
|
||||
nonce: Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
crypto_secretbox_open(
|
||||
ciphertext: Buffer,
|
||||
nonce: Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
crypto_secretbox_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_secretstream_xchacha20poly1305_init_push(
|
||||
key: CryptographyKey
|
||||
): Promise<crypto_secretstream_xchacha20poly1305_state>;
|
||||
crypto_secretstream_xchacha20poly1305_init_pull(
|
||||
key: Buffer,
|
||||
header: CryptographyKey
|
||||
): Promise<crypto_secretstream_xchacha20poly1305_state>;
|
||||
crypto_secretstream_xchacha20poly1305_push(
|
||||
state: crypto_secretstream_xchacha20poly1305_state,
|
||||
message: string | Buffer,
|
||||
ad?: string | Buffer,
|
||||
tag?: CryptoSecretStreamTagValues
|
||||
): Promise<Buffer>;
|
||||
crypto_secretstream_xchacha20poly1305_pull(
|
||||
state: crypto_secretstream_xchacha20poly1305_state,
|
||||
ciphertext: Buffer,
|
||||
ad?: string | Buffer,
|
||||
tag?: CryptoSecretStreamTagValues
|
||||
): Promise<Buffer>;
|
||||
crypto_secretstream_xchacha20poly1305_rekey(
|
||||
state: crypto_secretstream_xchacha20poly1305_state
|
||||
): Promise<void>;
|
||||
crypto_secretstream_xchacha20poly1305_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_shorthash(
|
||||
message: string | Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
crypto_shorthash_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_sign(
|
||||
message: string | Buffer,
|
||||
secretKey: Ed25519SecretKey
|
||||
): Promise<Buffer>;
|
||||
crypto_sign_open(
|
||||
message: string | Buffer,
|
||||
publicKey: Ed25519PublicKey
|
||||
): Promise<Buffer>;
|
||||
crypto_sign_detached(
|
||||
message: string | Buffer,
|
||||
secretKey: Ed25519SecretKey
|
||||
): Promise<Buffer>;
|
||||
crypto_sign_verify_detached(
|
||||
message: string | Buffer,
|
||||
publicKey: Ed25519PublicKey,
|
||||
signature: Buffer
|
||||
): Promise<boolean>;
|
||||
crypto_sign_secretkey(keypair: CryptographyKey): Promise<Ed25519SecretKey>;
|
||||
crypto_sign_publickey(keypair: CryptographyKey): Promise<Ed25519PublicKey>;
|
||||
crypto_sign_seed_keypair(seed: Buffer): Promise<CryptographyKey>;
|
||||
crypto_sign_keypair(): Promise<CryptographyKey>;
|
||||
|
||||
crypto_sign_ed25519_sk_to_curve25519(
|
||||
sk: Ed25519SecretKey
|
||||
): Promise<X25519SecretKey>;
|
||||
|
||||
crypto_sign_ed25519_pk_to_curve25519(
|
||||
pk: Ed25519PublicKey
|
||||
): Promise<X25519PublicKey>;
|
||||
|
||||
crypto_stream(
|
||||
length: number,
|
||||
nonce: Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
crypto_stream_xor(
|
||||
plaintext: string | Buffer,
|
||||
nonce: Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
crypto_stream_keygen(): Promise<CryptographyKey>;
|
||||
|
||||
randombytes_buf(num: number): Promise<Buffer>;
|
||||
randombytes_uniform(upperBound: number): Promise<number>;
|
||||
sodium_add(val: Buffer, addv: Buffer): Promise<Buffer>;
|
||||
sodium_bin2hex(encoded: Buffer): Promise<string>;
|
||||
sodium_compare(b1: Buffer, b2: Buffer): Promise<number>;
|
||||
sodium_hex2bin(encoded: Buffer|string): Promise<Buffer>;
|
||||
sodium_increment(buf: Buffer): Promise<Buffer>;
|
||||
sodium_is_zero(buf: Buffer, len: number): Promise<Buffer>;
|
||||
sodium_memcmp(b1: Buffer, b2: Buffer): Promise<boolean>;
|
||||
sodium_memzero(buf: Buffer): Promise<void>;
|
||||
sodium_pad(buf: string | Buffer, blockSize: number): Promise<Buffer>;
|
||||
sodium_unpad(buf: string | Buffer, blockSize: number): Promise<Buffer>;
|
||||
}
|
||||
|
||||
export class SodiumUtil {
|
||||
static cloneBuffer(buf: Buffer): Promise<Buffer>;
|
||||
static populateConstants<T>(anyobject: T): T & Constants;
|
||||
static toBuffer(
|
||||
stringOrBuffer: string | Buffer | Uint8Array | Promise<Buffer>
|
||||
): Promise<Buffer>;
|
||||
}
|
||||
|
||||
export class SodiumPolyfill {
|
||||
static crypto_onetimeauth(
|
||||
message: string | Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
static crypto_onetimeauth_verify(
|
||||
message: string | Buffer,
|
||||
key: CryptographyKey,
|
||||
tag: Buffer
|
||||
): Promise<boolean>;
|
||||
static crypto_stream_xor(
|
||||
plaintext: string | Buffer,
|
||||
nonce: Buffer,
|
||||
key: CryptographyKey
|
||||
): Promise<Buffer>;
|
||||
static crypto_pwhash_str_needs_rehash(
|
||||
hash: string | Buffer,
|
||||
opslimit: number,
|
||||
memlimit: number
|
||||
): Promise<boolean>;
|
||||
}
|
||||
}
|
||||
|
||||
export = Module;
|
36
library/sodium-plus/index.js
Normal file
36
library/sodium-plus/index.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
module.exports = {
|
||||
/**
|
||||
* This is only meant to be used for advanced users.
|
||||
*
|
||||
* A backend object can be passed to the SodiumPlus constructor.
|
||||
*
|
||||
* @param {string} type
|
||||
* @return {Backend}
|
||||
* @throws {SodiumError}
|
||||
* @throws {Error}
|
||||
*/
|
||||
getBackendObject: (type = '') => {
|
||||
if (type === 'SodiumNative') {
|
||||
// This one may error out. You should catch it in your code.
|
||||
// We won't here. Use the `await SodiumPlus.auto()` API instead!
|
||||
return require('./lib/backend/sodiumnative');
|
||||
} else if (type === 'LibsodiumWrappers') {
|
||||
return require('./lib/backend/libsodium-wrappers');
|
||||
} else if (type.length === 0) {
|
||||
return require('./lib/backend');
|
||||
}
|
||||
|
||||
// Default: Throw a SodiumError
|
||||
let SodiumError = require('./lib/sodium-error');
|
||||
throw new SodiumError(`Unrecognized backend type: ${type}`);
|
||||
},
|
||||
CryptographyKey: require('./lib/cryptography-key'),
|
||||
Ed25519PublicKey: require('./lib/keytypes/ed25519pk'),
|
||||
Ed25519SecretKey: require('./lib/keytypes/ed25519sk'),
|
||||
SodiumError: require('./lib/sodium-error'),
|
||||
SodiumPlus: require('./lib/sodiumplus'),
|
||||
SodiumPolyfill: require('./lib/polyfill'),
|
||||
SodiumUtil: require('./lib/util'),
|
||||
X25519PublicKey: require('./lib/keytypes/x25519pk'),
|
||||
X25519SecretKey: require('./lib/keytypes/x25519sk')
|
||||
};
|
32
library/sodium-plus/lib/backend.js
Normal file
32
library/sodium-plus/lib/backend.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const CryptographyKey = require('./cryptography-key');
|
||||
/* istanbul ignore if */
|
||||
if (typeof (Buffer) === 'undefined') {
|
||||
let Buffer = require('buffer/').Buffer;
|
||||
}
|
||||
|
||||
module.exports = class Backend {
|
||||
constructor() {
|
||||
// NOP
|
||||
this.backendName = 'UndefinedBackend';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CryptographyKey} sKey
|
||||
* @param {CryptographyKey} pKey
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_box_keypair_from_secretkey_and_publickey(sKey, pKey) {
|
||||
/* istanbul ignore if */
|
||||
if (sKey.getLength() !== 32) {
|
||||
throw new Error('Secret key must be 32 bytes');
|
||||
}
|
||||
/* istanbul ignore if */
|
||||
if (pKey.getLength() !== 32) {
|
||||
throw new Error('Public key must be 32 bytes');
|
||||
}
|
||||
const keypair = Buffer.alloc(64);
|
||||
sKey.getBuffer().copy(keypair, 0, 0, 32);
|
||||
pKey.getBuffer().copy(keypair, 32, 0, 32);
|
||||
return new CryptographyKey(Buffer.from(keypair));
|
||||
}
|
||||
};
|
782
library/sodium-plus/lib/backend/libsodium-wrappers.js
Normal file
782
library/sodium-plus/lib/backend/libsodium-wrappers.js
Normal file
|
@ -0,0 +1,782 @@
|
|||
const _sodium = require('libsodium-wrappers');
|
||||
const Backend = require('../backend');
|
||||
const CryptographyKey = require('../cryptography-key');
|
||||
const Polyfill = require('../polyfill');
|
||||
const Util = require('../util');
|
||||
const SodiumError = require('../sodium-error');
|
||||
const toBuffer = require('typedarray-to-buffer');
|
||||
/* istanbul ignore if */
|
||||
if (typeof (Buffer) === 'undefined') {
|
||||
let Buffer = require('buffer/').Buffer;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
module.exports = class LibsodiumWrappersBackend extends Backend {
|
||||
constructor(lib) {
|
||||
super(lib);
|
||||
this.sodium = lib;
|
||||
this.backendName = 'LibsodiumWrappersBackend';
|
||||
}
|
||||
|
||||
static async init() {
|
||||
await _sodium.ready;
|
||||
return new LibsodiumWrappersBackend(_sodium);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String|Buffer} ciphertext
|
||||
* @param {String|Buffer} assocData
|
||||
* @param {String|Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_aead_xchacha20poly1305_ietf_decrypt(ciphertext, assocData, nonce, key) {
|
||||
return toBuffer(
|
||||
this.sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
null,
|
||||
ciphertext,
|
||||
assocData,
|
||||
nonce,
|
||||
key.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String|Buffer} plaintext
|
||||
* @param {String|Buffer} assocData
|
||||
* @param {String|Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, assocData, nonce, key) {
|
||||
return toBuffer(
|
||||
this.sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
plaintext,
|
||||
assocData,
|
||||
null,
|
||||
nonce,
|
||||
key.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<buffer>}
|
||||
*/
|
||||
async crypto_auth(message, key) {
|
||||
return toBuffer(
|
||||
this.sodium.crypto_auth(
|
||||
message,
|
||||
key.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} mac
|
||||
* @param {String|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_auth_verify(mac, message, key) {
|
||||
return this.sodium.crypto_auth_verify(
|
||||
mac,
|
||||
message,
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} sk
|
||||
* @param {CryptographyKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*
|
||||
*/
|
||||
async crypto_box(plaintext, nonce, sk, pk) {
|
||||
return Util.toBuffer(
|
||||
await this.sodium.crypto_box_easy(
|
||||
await Util.toBuffer(plaintext),
|
||||
await Util.toBuffer(nonce),
|
||||
pk.getBuffer(),
|
||||
sk.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} sk
|
||||
* @param {CryptographyKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_box_open(ciphertext, nonce, sk, pk) {
|
||||
return Util.toBuffer(
|
||||
await this.sodium.crypto_box_open_easy(
|
||||
await Util.toBuffer(ciphertext),
|
||||
await Util.toBuffer(nonce),
|
||||
pk.getBuffer(),
|
||||
sk.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {CryptographyKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*
|
||||
*/
|
||||
async crypto_box_seal(plaintext, pk) {
|
||||
return Util.toBuffer(
|
||||
await this.sodium.crypto_box_seal(
|
||||
await Util.toBuffer(plaintext),
|
||||
pk.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {CryptographyKey} pk
|
||||
* @param {CryptographyKey} sk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_box_seal_open(ciphertext, pk, sk) {
|
||||
return Util.toBuffer(
|
||||
await this.sodium.crypto_box_seal_open(
|
||||
await Util.toBuffer(ciphertext),
|
||||
pk.getBuffer(),
|
||||
sk.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_box_keypair() {
|
||||
const obj = this.sodium.crypto_box_keypair();
|
||||
return new CryptographyKey(
|
||||
Buffer.concat([
|
||||
await Util.toBuffer(obj.privateKey),
|
||||
await Util.toBuffer(obj.publicKey)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey|null} key
|
||||
* @param {number} outputLength
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_generichash(message, key = null, outputLength = 32) {
|
||||
if (key) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_generichash(
|
||||
outputLength,
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_generichash(
|
||||
outputLength,
|
||||
await Util.toBuffer(message)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CryptographyKey|null} key
|
||||
* @param {number} outputLength
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_generichash_init(key = null, outputLength = 32) {
|
||||
if (key) {
|
||||
return this.sodium.crypto_generichash_init(key.getBuffer(), outputLength);
|
||||
}
|
||||
return this.sodium.crypto_generichash_init(null, outputLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {string|Buffer} message
|
||||
* @return {Promise<*>}
|
||||
*/
|
||||
async crypto_generichash_update(state, message) {
|
||||
return this.sodium.crypto_generichash_update(state, await Util.toBuffer(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {number} outputLength
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_generichash_final(state, outputLength = 32) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_generichash_final(state, outputLength)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {X25519PublicKey} clientPublicKey
|
||||
* @param {X25519SecretKey} clientSecretKey
|
||||
* @param {X25519PublicKey} serverPublicKey
|
||||
* @return {Promise<CryptographyKey[]>}
|
||||
*/
|
||||
async crypto_kx_client_session_keys(clientPublicKey, clientSecretKey, serverPublicKey) {
|
||||
const gen = this.sodium.crypto_kx_client_session_keys(
|
||||
clientPublicKey.getBuffer(),
|
||||
clientSecretKey.getBuffer(),
|
||||
serverPublicKey.getBuffer(),
|
||||
);
|
||||
return [
|
||||
new CryptographyKey(await Util.toBuffer(gen.sharedRx)),
|
||||
new CryptographyKey(await Util.toBuffer(gen.sharedTx))
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {X25519PublicKey} serverPublicKey
|
||||
* @param {X25519SecretKey} serverSecretKey
|
||||
* @param {X25519PublicKey} clientPublicKey
|
||||
* @return {Promise<CryptographyKey[]>}
|
||||
*/
|
||||
async crypto_kx_server_session_keys(serverPublicKey, serverSecretKey, clientPublicKey) {
|
||||
const gen = this.sodium.crypto_kx_server_session_keys(
|
||||
serverPublicKey.getBuffer(),
|
||||
serverSecretKey.getBuffer(),
|
||||
clientPublicKey.getBuffer(),
|
||||
);
|
||||
return [
|
||||
new CryptographyKey(await Util.toBuffer(gen.sharedRx)),
|
||||
new CryptographyKey(await Util.toBuffer(gen.sharedTx))
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} length
|
||||
* @param {number} subKeyId
|
||||
* @param {string|Buffer} context
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_kdf_derive_from_key(length, subKeyId, context, key) {
|
||||
return new CryptographyKey(
|
||||
await Util.toBuffer(
|
||||
this.sodium.crypto_kdf_derive_from_key(
|
||||
length,
|
||||
subKeyId | 0,
|
||||
context,
|
||||
key.getBuffer()
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_onetimeauth(message, key) {
|
||||
if (typeof this.sodium.crypto_onetimeauth === 'undefined') {
|
||||
return Polyfill.crypto_onetimeauth(
|
||||
await Util.toBuffer(message),
|
||||
key
|
||||
);
|
||||
}
|
||||
return this.sodium.crypto_onetimeauth(
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @param {Buffer} tag
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_onetimeauth_verify(message, key, tag) {
|
||||
if (typeof this.sodium.crypto_onetimeauth_verify === 'undefined') {
|
||||
return Polyfill.crypto_onetimeauth_verify(
|
||||
await Util.toBuffer(message),
|
||||
key,
|
||||
tag
|
||||
);
|
||||
}
|
||||
return this.sodium.crypto_onetimeauth_verify(
|
||||
tag,
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} length
|
||||
* @param {string|Buffer} password
|
||||
* @param {Buffer} salt
|
||||
* @param {number} opslimit
|
||||
* @param {number} memlimit
|
||||
* @param {number} algorithm
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_pwhash(length, password, salt, opslimit, memlimit, algorithm) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_pwhash(
|
||||
length,
|
||||
await Util.toBuffer(password),
|
||||
await Util.toBuffer(salt),
|
||||
opslimit,
|
||||
memlimit,
|
||||
algorithm
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} password
|
||||
* @param {number} opslimit
|
||||
* @param {number} memlimit
|
||||
* @return {Promise<string>}
|
||||
*/
|
||||
async crypto_pwhash_str(password, opslimit, memlimit) {
|
||||
return (await Util.toBuffer(
|
||||
this.sodium.crypto_pwhash_str(
|
||||
await Util.toBuffer(password),
|
||||
opslimit,
|
||||
memlimit
|
||||
))
|
||||
).toString('utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} password
|
||||
* @param {string|Buffer} hash
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_pwhash_str_verify(password, hash) {
|
||||
return this.sodium.crypto_pwhash_str_verify(
|
||||
hash.toString('utf-8'),
|
||||
await Util.toBuffer(password)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} hash
|
||||
* @param {number} opslimit
|
||||
* @param {number} memlimit
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_pwhash_str_needs_rehash(hash, opslimit, memlimit) {
|
||||
if (typeof (this.sodium.crypto_pwhash_str_needs_rehash) !== 'function') {
|
||||
return await Polyfill.crypto_pwhash_str_needs_rehash(hash, opslimit, memlimit);
|
||||
}
|
||||
return this.sodium.crypto_pwhash_str_needs_rehash(hash, opslimit, memlimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {X25519SecretKey} secretKey
|
||||
* @param {X25519PublicKey} publicKey
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_scalarmult(secretKey, publicKey) {
|
||||
return new CryptographyKey(
|
||||
await Util.toBuffer(
|
||||
this.sodium.crypto_scalarmult(secretKey.getBuffer(), publicKey.getBuffer())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretbox(plaintext, nonce, key) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_secretbox_easy(
|
||||
await Util.toBuffer(plaintext),
|
||||
nonce,
|
||||
key.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretbox_open(ciphertext, nonce, key) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_secretbox_open_easy(
|
||||
await Util.toBuffer(ciphertext),
|
||||
nonce,
|
||||
key.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_shorthash(message, key) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_shorthash(
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message,
|
||||
* @param {Ed25519SecretKey} secretKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign(message, secretKey) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_sign(
|
||||
await Util.toBuffer(message),
|
||||
secretKey.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message,
|
||||
* @param {Ed25519PublicKey} publicKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_open(message, publicKey) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_sign_open(
|
||||
message,
|
||||
publicKey.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @param {string|Buffer} message,
|
||||
* @param {Ed25519SecretKey} secretKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_detached(message, secretKey) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_sign_detached(
|
||||
await Util.toBuffer(message),
|
||||
secretKey.getBuffer()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message,
|
||||
* @param {Ed25519PublicKey} publicKey
|
||||
* @param {Buffer} signature
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_verify_detached(message, publicKey, signature) {
|
||||
return this.sodium.crypto_sign_verify_detached(
|
||||
signature,
|
||||
await Util.toBuffer(message),
|
||||
publicKey.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_sign_keypair() {
|
||||
const obj = this.sodium.crypto_sign_keypair();
|
||||
return new CryptographyKey(
|
||||
Buffer.concat([
|
||||
await Util.toBuffer(obj.privateKey),
|
||||
await Util.toBuffer(obj.publicKey)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} seed
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_sign_seed_keypair(seed) {
|
||||
const obj = this.sodium.crypto_sign_seed_keypair(seed);
|
||||
return new CryptographyKey(
|
||||
Buffer.concat([
|
||||
await Util.toBuffer(obj.privateKey),
|
||||
await Util.toBuffer(obj.publicKey)
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Ed25519SecretKey} sk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_ed25519_sk_to_curve25519(sk) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_sign_ed25519_sk_to_curve25519(sk.getBuffer())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Ed25519PublicKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_ed25519_pk_to_curve25519(pk) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_sign_ed25519_pk_to_curve25519(pk.getBuffer())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} length
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_stream(length, nonce, key) {
|
||||
if (typeof (this.sodium.crypto_stream_xor) === 'undefined') {
|
||||
return Polyfill.crypto_stream_xor(
|
||||
Buffer.alloc(length, 0),
|
||||
await Util.toBuffer(nonce),
|
||||
key
|
||||
);
|
||||
}
|
||||
return this.sodium.crypto_stream(
|
||||
length,
|
||||
await Util.toBuffer(nonce),
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_stream_xor(plaintext, nonce, key) {
|
||||
if (typeof (this.sodium.crypto_stream_xor) === 'undefined') {
|
||||
return Polyfill.crypto_stream_xor(
|
||||
await Util.toBuffer(plaintext),
|
||||
await Util.toBuffer(nonce),
|
||||
key
|
||||
)
|
||||
}
|
||||
return this.sodium.crypto_stream_xor(
|
||||
await Util.toBuffer(plaintext),
|
||||
await Util.toBuffer(nonce),
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {CryptographyKey} secretKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_scalarmult_base(secretKey) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_scalarmult_base(secretKey.getBuffer())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<array>} [state, header]
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_init_push(key) {
|
||||
const res = this.sodium.crypto_secretstream_xchacha20poly1305_init_push(key.getBuffer());
|
||||
return [res.state, await Util.toBuffer(res.header)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} header
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<*>} Returns the opaque state object
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_init_pull(header, key) {
|
||||
if (header.length !== this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
|
||||
throw new SodiumError(`Header must be ${this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES} bytes long`);
|
||||
}
|
||||
return this.sodium.crypto_secretstream_xchacha20poly1305_init_pull(header, key.getBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {string|Buffer} message
|
||||
* @param {string|Buffer} ad
|
||||
* @param {number} tag
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_push(state, message, ad = '', tag = 0) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.crypto_secretstream_xchacha20poly1305_push(
|
||||
state,
|
||||
await Util.toBuffer(message),
|
||||
ad.length > 0 ? (await Util.toBuffer(ad)) : null,
|
||||
tag
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {string|Buffer} ad
|
||||
* @param {number} tag
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_pull(state, ciphertext, ad = '', tag = 0) {
|
||||
if (ciphertext.length < this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES) {
|
||||
throw new SodiumError('Invalid ciphertext size');
|
||||
}
|
||||
const out = this.sodium.crypto_secretstream_xchacha20poly1305_pull(
|
||||
state,
|
||||
await Util.toBuffer(ciphertext),
|
||||
ad.length > 0 ? (await Util.toBuffer(ad)) : null,
|
||||
tag
|
||||
);
|
||||
if (tag !== out.tag) {
|
||||
throw new SodiumError(`Invalid tag (Given: ${tag}; Expected: ${out.tag})`);
|
||||
}
|
||||
return Util.toBuffer(out.message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_rekey(state) {
|
||||
this.sodium.crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} number
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async randombytes_buf(number) {
|
||||
return Util.toBuffer(await this.sodium.randombytes_buf(number));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} upperBound
|
||||
* @return {Promise<number>}
|
||||
*/
|
||||
async randombytes_uniform(upperBound) {
|
||||
return this.sodium.randombytes_uniform(upperBound);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} val
|
||||
* @param {Uint8Array} addv
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_add(val, addv) {
|
||||
const buf = await Util.cloneBuffer(val);
|
||||
this.sodium.add(buf, addv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} buf
|
||||
* @return {Promise<string>}
|
||||
*/
|
||||
async sodium_bin2hex(buf) {
|
||||
return this.sodium.to_hex(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} b1
|
||||
* @param {Buffer} b2
|
||||
* @return {Promise<number>}
|
||||
*/
|
||||
async sodium_compare(b1, b2) {
|
||||
return this.sodium.compare(b1, b2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer|string} encoded
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_hex2bin(encoded) {
|
||||
return Buffer.from(this.sodium.from_hex(encoded));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} buf
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_increment(buf) {
|
||||
return this.sodium.increment(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} buf
|
||||
* @param {number} len
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_is_zero(buf, len) {
|
||||
return this.sodium.is_zero(buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} b1
|
||||
* @param {Buffer} b2
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async sodium_memcmp(b1, b2) {
|
||||
return this.sodium.memcmp(b1, b2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} buf
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async sodium_memzero(buf) {
|
||||
this.sodium.memzero(buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string|Buffer} buf
|
||||
* @param {number} blockSize
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_pad(buf, blockSize) {
|
||||
return Util.toBuffer(
|
||||
this.sodium.pad(await Util.toBuffer(buf), blockSize)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string|Buffer} buf
|
||||
* @param {number} blockSize
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_unpad(buf, blockSize) {
|
||||
return Util.toBuffer(this.sodium.unpad(buf, blockSize));
|
||||
}
|
||||
};
|
866
library/sodium-plus/lib/backend/sodiumnative.js
Normal file
866
library/sodium-plus/lib/backend/sodiumnative.js
Normal file
|
@ -0,0 +1,866 @@
|
|||
let loaded = false;
|
||||
let _sodium;
|
||||
/* istanbul ignore next */
|
||||
try {
|
||||
_sodium = require('sodium-native');
|
||||
loaded = true;
|
||||
} catch (e) {
|
||||
_sodium = {};
|
||||
}
|
||||
const Backend = require('../backend');
|
||||
const CryptographyKey = require('../cryptography-key');
|
||||
const SodiumError = require('../sodium-error');
|
||||
const Util = require('../util');
|
||||
const toBuffer = require('typedarray-to-buffer');
|
||||
/* istanbul ignore if */
|
||||
if (typeof (Buffer) === 'undefined') {
|
||||
let Buffer = require('buffer/').Buffer;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
module.exports = class SodiumNativeBackend extends Backend {
|
||||
constructor(lib) {
|
||||
super(lib);
|
||||
this.sodium = lib;
|
||||
this.backendName = 'SodiumNativeBackend';
|
||||
}
|
||||
|
||||
static async init() {
|
||||
if (!loaded) {
|
||||
throw new SodiumError('sodium-native not installed');
|
||||
}
|
||||
return new SodiumNativeBackend(_sodium);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String|Buffer} ciphertext
|
||||
* @param {String|Buffer} assocData
|
||||
* @param {String|Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_aead_xchacha20poly1305_ietf_decrypt(ciphertext, assocData, nonce, key) {
|
||||
const plaintext = Buffer.alloc(ciphertext.length - 16, 0);
|
||||
this.sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
plaintext,
|
||||
null,
|
||||
await Util.toBuffer(ciphertext),
|
||||
await Util.toBuffer(assocData),
|
||||
await Util.toBuffer(nonce),
|
||||
key.getBuffer()
|
||||
);
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String|Buffer} plaintext
|
||||
* @param {String|Buffer} assocData
|
||||
* @param {String|Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, assocData, nonce, key) {
|
||||
const ciphertext = Buffer.alloc(plaintext.length + 16, 0);
|
||||
this.sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
|
||||
ciphertext,
|
||||
await Util.toBuffer(plaintext),
|
||||
await Util.toBuffer(assocData),
|
||||
null,
|
||||
await Util.toBuffer(nonce),
|
||||
key.getBuffer()
|
||||
);
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<buffer>}
|
||||
*/
|
||||
async crypto_auth(message, key) {
|
||||
const output = Buffer.alloc(32);
|
||||
this.sodium.crypto_auth(
|
||||
output,
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
return toBuffer(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} mac
|
||||
* @param {String|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_auth_verify(mac, message, key) {
|
||||
return this.sodium.crypto_auth_verify(
|
||||
mac,
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} sk
|
||||
* @param {CryptographyKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*
|
||||
*/
|
||||
async crypto_box(plaintext, nonce, sk, pk) {
|
||||
const ciphertext = Buffer.alloc(plaintext.length + 16);
|
||||
this.sodium.crypto_box_easy(
|
||||
ciphertext,
|
||||
await Util.toBuffer(plaintext),
|
||||
nonce,
|
||||
pk.getBuffer(),
|
||||
sk.getBuffer()
|
||||
);
|
||||
return Util.toBuffer(ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} sk
|
||||
* @param {CryptographyKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_box_open(ciphertext, nonce, sk, pk) {
|
||||
const plaintext = Buffer.alloc(ciphertext.length - 16);
|
||||
const success = this.sodium.crypto_box_open_easy(
|
||||
plaintext,
|
||||
ciphertext,
|
||||
nonce,
|
||||
pk.getBuffer(),
|
||||
sk.getBuffer()
|
||||
);
|
||||
if (!success) {
|
||||
throw new SodiumError('Decryption failed');
|
||||
}
|
||||
return Util.toBuffer(plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {CryptographyKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*
|
||||
*/
|
||||
async crypto_box_seal(plaintext, pk) {
|
||||
const ciphertext = Buffer.alloc(plaintext.length + 48);
|
||||
this.sodium.crypto_box_seal(
|
||||
ciphertext,
|
||||
await Util.toBuffer(plaintext),
|
||||
pk.getBuffer()
|
||||
);
|
||||
return Util.toBuffer(ciphertext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {CryptographyKey} pk
|
||||
* @param {CryptographyKey} sk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_box_seal_open(ciphertext, pk, sk) {
|
||||
const plaintext = Buffer.alloc(ciphertext.length - 48);
|
||||
const success = this.sodium.crypto_box_seal_open(
|
||||
plaintext,
|
||||
await Util.toBuffer(ciphertext),
|
||||
pk.getBuffer(),
|
||||
sk.getBuffer()
|
||||
);
|
||||
if (!success) {
|
||||
throw new SodiumError('Decryption failed');
|
||||
}
|
||||
return Util.toBuffer(plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_box_keypair() {
|
||||
const sK = Buffer.alloc(32, 0);
|
||||
const pK = Buffer.alloc(32, 0);
|
||||
this.sodium.crypto_box_keypair(sK, pK);
|
||||
return new CryptographyKey(
|
||||
Buffer.concat([pK, sK])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey|null} key
|
||||
* @param {number} outputLength
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_generichash(message, key = null, outputLength = 32) {
|
||||
const hash = Buffer.alloc(outputLength);
|
||||
if (key) {
|
||||
this.sodium.crypto_generichash(hash, await Util.toBuffer(message), key.getBuffer());
|
||||
} else {
|
||||
this.sodium.crypto_generichash(hash, await Util.toBuffer(message));
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CryptographyKey|null} key
|
||||
* @param {number} outputLength
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_generichash_init(key = null, outputLength = 32) {
|
||||
const state = Buffer.alloc(this.CRYPTO_GENERICHASH_STATEBYTES);
|
||||
if (key) {
|
||||
this.sodium.crypto_generichash_init(state, key.getBuffer(), outputLength);
|
||||
} else {
|
||||
this.sodium.crypto_generichash_init(state, null, outputLength);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {string|Buffer} message
|
||||
* @return {Promise<*>}
|
||||
*/
|
||||
async crypto_generichash_update(state, message) {
|
||||
this.sodium.crypto_generichash_update(state, await Util.toBuffer(message));
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {number} outputLength
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_generichash_final(state, outputLength = 32) {
|
||||
const output = Buffer.alloc(outputLength);
|
||||
this.sodium.crypto_generichash_final(state, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} length
|
||||
* @param {number} subKeyId
|
||||
* @param {string|Buffer} context
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_kdf_derive_from_key(length, subKeyId, context, key) {
|
||||
const subkey = Buffer.alloc(length, 0);
|
||||
this.sodium.crypto_kdf_derive_from_key(
|
||||
subkey,
|
||||
subKeyId | 0,
|
||||
await Util.toBuffer(context),
|
||||
key.getBuffer()
|
||||
);
|
||||
return new CryptographyKey(subkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {X25519PublicKey} clientPublicKey
|
||||
* @param {X25519SecretKey} clientSecretKey
|
||||
* @param {X25519PublicKey} serverPublicKey
|
||||
* @return {Promise<CryptographyKey[]>}
|
||||
*/
|
||||
async crypto_kx_client_session_keys(clientPublicKey, clientSecretKey, serverPublicKey) {
|
||||
const rx = Buffer.alloc(this.CRYPTO_KX_SESSIONKEYBYTES);
|
||||
const tx = Buffer.alloc(this.CRYPTO_KX_SESSIONKEYBYTES);
|
||||
this.sodium.crypto_kx_client_session_keys(
|
||||
rx,
|
||||
tx,
|
||||
clientPublicKey.getBuffer(),
|
||||
clientSecretKey.getBuffer(),
|
||||
serverPublicKey.getBuffer(),
|
||||
);
|
||||
return [
|
||||
new CryptographyKey(rx),
|
||||
new CryptographyKey(tx)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {X25519PublicKey} serverPublicKey
|
||||
* @param {X25519SecretKey} serverSecretKey
|
||||
* @param {X25519PublicKey} clientPublicKey
|
||||
* @return {Promise<CryptographyKey[]>}
|
||||
*/
|
||||
async crypto_kx_server_session_keys(serverPublicKey, serverSecretKey, clientPublicKey) {
|
||||
const rx = Buffer.alloc(this.CRYPTO_KX_SESSIONKEYBYTES);
|
||||
const tx = Buffer.alloc(this.CRYPTO_KX_SESSIONKEYBYTES);
|
||||
this.sodium.crypto_kx_server_session_keys(
|
||||
rx,
|
||||
tx,
|
||||
serverPublicKey.getBuffer(),
|
||||
serverSecretKey.getBuffer(),
|
||||
clientPublicKey.getBuffer(),
|
||||
);
|
||||
return [
|
||||
new CryptographyKey(rx),
|
||||
new CryptographyKey(tx)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_onetimeauth(message, key) {
|
||||
const output = Buffer.alloc(16);
|
||||
this.sodium.crypto_onetimeauth(
|
||||
output,
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @param {Buffer} tag
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_onetimeauth_verify(message, key, tag) {
|
||||
return this.sodium.crypto_onetimeauth_verify(
|
||||
tag,
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} length
|
||||
* @param {string|Buffer} password
|
||||
* @param {Buffer} salt
|
||||
* @param {number} opslimit
|
||||
* @param {number} memlimit
|
||||
* @param {number} algorithm
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_pwhash(length, password, salt, opslimit, memlimit, algorithm) {
|
||||
const hashed = Buffer.alloc(length, 0);
|
||||
const bufPass = await Util.toBuffer(password);
|
||||
const bufSalt = await Util.toBuffer(salt);
|
||||
await new Promise((resolve, reject) => {
|
||||
this.sodium.crypto_pwhash_async(
|
||||
hashed,
|
||||
bufPass,
|
||||
bufSalt,
|
||||
opslimit,
|
||||
memlimit,
|
||||
algorithm,
|
||||
(e, res) => {
|
||||
if (e) return reject(e);
|
||||
return resolve(res);
|
||||
}
|
||||
);
|
||||
});
|
||||
return hashed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} password
|
||||
* @param {number} opslimit
|
||||
* @param {number} memlimit
|
||||
* @return {Promise<string>}
|
||||
*/
|
||||
async crypto_pwhash_str(password, opslimit, memlimit) {
|
||||
const hashed = Buffer.alloc(128, 0);
|
||||
const bufPass = await Util.toBuffer(password);
|
||||
await new Promise((resolve, reject) => {
|
||||
this.sodium.crypto_pwhash_str_async(
|
||||
hashed,
|
||||
bufPass,
|
||||
opslimit,
|
||||
memlimit,
|
||||
(e, res) => {
|
||||
if (e) return reject(e);
|
||||
return resolve(res);
|
||||
}
|
||||
);
|
||||
});
|
||||
return hashed.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} password
|
||||
* @param {string|Buffer} hash
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_pwhash_str_verify(password, hash) {
|
||||
const allocated = Buffer.alloc(128, 0);
|
||||
(await Util.toBuffer(hash)).copy(allocated, 0, 0);
|
||||
const bufPass = await Util.toBuffer(password);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.sodium.crypto_pwhash_str_verify_async(
|
||||
allocated,
|
||||
bufPass,
|
||||
(e, res) => {
|
||||
if (e) return reject(e);
|
||||
return resolve(res);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} hash
|
||||
* @param {number} opslimit
|
||||
* @param {number} memlimit
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async crypto_pwhash_str_needs_rehash(hash, opslimit, memlimit) {
|
||||
const allocated = Buffer.alloc(128, 0);
|
||||
(await Util.toBuffer(hash)).copy(allocated, 0, 0);
|
||||
return this.sodium.crypto_pwhash_str_needs_rehash(
|
||||
allocated,
|
||||
opslimit,
|
||||
memlimit
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {X25519SecretKey} secretKey
|
||||
* @param {X25519PublicKey} publicKey
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_scalarmult(secretKey, publicKey) {
|
||||
const shared = Buffer.alloc(32);
|
||||
this.sodium.crypto_scalarmult(shared, secretKey.getBuffer(), publicKey.getBuffer());
|
||||
return new CryptographyKey(
|
||||
await Util.toBuffer(shared)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {CryptographyKey} secretKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_scalarmult_base(secretKey) {
|
||||
const buf = Buffer.alloc(32);
|
||||
this.sodium.crypto_scalarmult_base(buf, secretKey.getBuffer());
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretbox(plaintext, nonce, key) {
|
||||
const encrypted = Buffer.alloc(plaintext.length + 16);
|
||||
this.sodium.crypto_secretbox_easy(
|
||||
encrypted,
|
||||
await Util.toBuffer(plaintext),
|
||||
nonce,
|
||||
key.getBuffer()
|
||||
);
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_shorthash(message, key) {
|
||||
const output = Buffer.alloc(8);
|
||||
this.sodium.crypto_shorthash(
|
||||
output,
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretbox_open(ciphertext, nonce, key) {
|
||||
const decrypted = Buffer.alloc(ciphertext.length - 16);
|
||||
if (!this.sodium.crypto_secretbox_open_easy(
|
||||
decrypted,
|
||||
ciphertext,
|
||||
nonce,
|
||||
key.getBuffer()
|
||||
)) {
|
||||
throw new SodiumError('Decryption failure');
|
||||
}
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<array>} [state, header]
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_init_push(key) {
|
||||
const state = Buffer.alloc(this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_STATEBYTES);
|
||||
const header = Buffer.alloc(this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES);
|
||||
this.sodium.randombytes_buf(header);
|
||||
this.sodium.crypto_secretstream_xchacha20poly1305_init_push(state, header, key.getBuffer());
|
||||
return [state, header];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} header
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<*>} Returns the opaque state object
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_init_pull(header, key) {
|
||||
if (header.length !== this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
|
||||
throw new SodiumError(`Header must be ${this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES} bytes long`);
|
||||
}
|
||||
const state = Buffer.alloc(this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_STATEBYTES);
|
||||
this.sodium.crypto_secretstream_xchacha20poly1305_init_pull(state, header, key.getBuffer());
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {string|Buffer} message
|
||||
* @param {string|Buffer} ad
|
||||
* @param {number} tag
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_push(state, message, ad = '', tag = 0) {
|
||||
const ciphertext = Buffer.alloc(message.length + this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES);
|
||||
this.sodium.crypto_secretstream_xchacha20poly1305_push(
|
||||
state,
|
||||
ciphertext,
|
||||
await Util.toBuffer(message),
|
||||
ad.length > 0 ? (await Util.toBuffer(ad)) : null,
|
||||
Buffer.from([tag])
|
||||
);
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @param {Buffer} ciphertext
|
||||
* @param {string|Buffer} ad
|
||||
* @param {number} tag
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_pull(state, ciphertext, ad = '', tag = 0) {
|
||||
if (ciphertext.length < this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES) {
|
||||
throw new SodiumError('Invalid ciphertext size');
|
||||
}
|
||||
const plaintext = Buffer.alloc(ciphertext.length - this.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES);
|
||||
this.sodium.crypto_secretstream_xchacha20poly1305_pull(
|
||||
state,
|
||||
plaintext,
|
||||
Buffer.from([tag]),
|
||||
ciphertext,
|
||||
ad.length > 0 ? (await Util.toBuffer(ad)) : null
|
||||
);
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} state
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async crypto_secretstream_xchacha20poly1305_rekey(state) {
|
||||
this.sodium.crypto_secretstream_xchacha20poly1305_rekey(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message,
|
||||
* @param {Ed25519SecretKey} secretKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign(message, secretKey) {
|
||||
const signed = Buffer.alloc(message.length + 64);
|
||||
this.sodium.crypto_sign(signed, await Util.toBuffer(message), secretKey.getBuffer());
|
||||
return signed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} signedMessage,
|
||||
* @param {Ed25519PublicKey} publicKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_open(signedMessage, publicKey) {
|
||||
const original = Buffer.alloc(signedMessage.length - 64);
|
||||
this.sodium.crypto_sign_open(original, await Util.toBuffer(signedMessage), publicKey.getBuffer());
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message,
|
||||
* @param {Ed25519SecretKey} secretKey
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_detached(message, secretKey) {
|
||||
const signature = Buffer.alloc(64);
|
||||
this.sodium.crypto_sign_detached(signature, await Util.toBuffer(message), secretKey.getBuffer());
|
||||
return signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message,
|
||||
* @param {Ed25519PublicKey} publicKey
|
||||
* @param {Buffer} signature
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_verify_detached(message, publicKey, signature) {
|
||||
return this.sodium.crypto_sign_verify_detached(
|
||||
signature,
|
||||
await Util.toBuffer(message),
|
||||
publicKey.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_sign_keypair() {
|
||||
const sK = Buffer.alloc(64, 0);
|
||||
const pK = Buffer.alloc(32, 0);
|
||||
this.sodium.crypto_sign_keypair(pK, sK);
|
||||
return new CryptographyKey(
|
||||
Buffer.concat([sK, pK])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} seed
|
||||
* @return {Promise<CryptographyKey>}
|
||||
*/
|
||||
async crypto_sign_seed_keypair(seed) {
|
||||
const sK = Buffer.alloc(64, 0);
|
||||
const pK = Buffer.alloc(32, 0);
|
||||
this.sodium.crypto_sign_seed_keypair(pK, sK, seed);
|
||||
return new CryptographyKey(
|
||||
Buffer.concat([sK, pK])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Ed25519SecretKey} sk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_ed25519_sk_to_curve25519(sk) {
|
||||
const xsk = Buffer.alloc(32);
|
||||
this.sodium.crypto_sign_ed25519_sk_to_curve25519(xsk, sk.getBuffer());
|
||||
return xsk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Ed25519PublicKey} pk
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_sign_ed25519_pk_to_curve25519(pk) {
|
||||
const xpk = Buffer.alloc(32);
|
||||
this.sodium.crypto_sign_ed25519_pk_to_curve25519(xpk, pk.getBuffer());
|
||||
return xpk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} length
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_stream(length, nonce, key) {
|
||||
const output = Buffer.alloc(length);
|
||||
this.sodium.crypto_stream(
|
||||
output,
|
||||
await Util.toBuffer(nonce),
|
||||
key.getBuffer()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async crypto_stream_xor(plaintext, nonce, key) {
|
||||
const output = Buffer.alloc(plaintext.length);
|
||||
this.sodium.crypto_stream_xor(
|
||||
output,
|
||||
await Util.toBuffer(plaintext),
|
||||
await Util.toBuffer(nonce),
|
||||
key.getBuffer()
|
||||
);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} number
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async randombytes_buf(number) {
|
||||
let buf = Buffer.alloc(number);
|
||||
this.sodium.randombytes_buf(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} upperBound
|
||||
* @return {Promise<number>}
|
||||
*/
|
||||
async randombytes_uniform(upperBound) {
|
||||
return this.sodium.randombytes_uniform(upperBound);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} val
|
||||
* @param {Uint8Array} addv
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_add(val, addv) {
|
||||
const buf = await Util.cloneBuffer(val);
|
||||
this.sodium.sodium_add(buf, addv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} input
|
||||
* @return {Promise<string>}
|
||||
*/
|
||||
async sodium_bin2hex(input) {
|
||||
let str = "", b, c, x;
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
c = input[i] & 0xf;
|
||||
b = input[i] >>> 4;
|
||||
x =
|
||||
((87 + c + (((c - 10) >> 8) & ~38)) << 8) |
|
||||
(87 + b + (((b - 10) >> 8) & ~38));
|
||||
str += String.fromCharCode(x & 0xff) + String.fromCharCode(x >>> 8);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} b1
|
||||
* @param {Buffer} b2
|
||||
* @return {Promise<number>}
|
||||
*/
|
||||
async sodium_compare(b1, b2) {
|
||||
return this.sodium.sodium_compare(b1, b2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer|string} hex
|
||||
* @param {string|null} ignore
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_hex2bin(hex, ignore = null) {
|
||||
let bin_pos = 0,
|
||||
hex_pos = 0,
|
||||
c = 0,
|
||||
c_acc = 0,
|
||||
c_alpha0 = 0,
|
||||
c_alpha = 0,
|
||||
c_num0 = 0,
|
||||
c_num = 0,
|
||||
c_val = 0,
|
||||
state = 0;
|
||||
const bin = Buffer.alloc(hex.length >> 1, 0);
|
||||
|
||||
while (hex_pos < hex.length) {
|
||||
c = hex.charCodeAt(hex_pos);
|
||||
c_num = c ^ 48;
|
||||
c_num0 = (c_num - 10) >> 8;
|
||||
c_alpha = (c & ~32) - 55;
|
||||
c_alpha0 = ((c_alpha - 10) ^ (c_alpha - 16)) >> 8;
|
||||
if ((c_num0 | c_alpha0) === 0) {
|
||||
if (ignore && state === 0 && ignore.indexOf(c) >= 0) {
|
||||
hex_pos++;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
|
||||
if (state === 0) {
|
||||
c_acc = c_val * 16;
|
||||
} else {
|
||||
bin[bin_pos++] = c_acc | c_val;
|
||||
}
|
||||
state = ~state;
|
||||
hex_pos++;
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} buf
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_increment(buf) {
|
||||
return this.sodium.sodium_increment(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} buf
|
||||
* @param {number} len
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_is_zero(buf, len) {
|
||||
return this.sodium.sodium_is_zero(buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} b1
|
||||
* @param {Buffer} b2
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
async sodium_memcmp(b1, b2) {
|
||||
return this.sodium.sodium_memcmp(b1, b2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} buf
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async sodium_memzero(buf) {
|
||||
this.sodium.sodium_memzero(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} buf
|
||||
* @param {number} blockSize
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_pad(buf, blockSize) {
|
||||
buf = await Util.toBuffer(buf);
|
||||
let length = buf.length + (buf.length % blockSize);
|
||||
if (length < blockSize) {
|
||||
length += blockSize;
|
||||
}
|
||||
const padded = Buffer.alloc(length + 100);
|
||||
buf.copy(padded, 0, 0);
|
||||
const sliceto = this.sodium.sodium_pad(padded, buf.length, blockSize);
|
||||
return padded.slice(0, sliceto);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string|Buffer} buf
|
||||
* @param {number} blockSize
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
async sodium_unpad(buf, blockSize) {
|
||||
const outlen = this.sodium.sodium_unpad(buf, buf.length, blockSize);
|
||||
return buf.slice(0, outlen);
|
||||
}
|
||||
};
|
80
library/sodium-plus/lib/cryptography-key.js
Normal file
80
library/sodium-plus/lib/cryptography-key.js
Normal file
|
@ -0,0 +1,80 @@
|
|||
"use strict";
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (typeof (Buffer) === 'undefined') {
|
||||
let Buffer = require('buffer/').Buffer;
|
||||
}
|
||||
module.exports = class CryptographyKey {
|
||||
/**
|
||||
* Note: We use Object.defineProperty() to hide the buffer inside of the
|
||||
* CryptographyKey object to prevent accidental leaks.
|
||||
*
|
||||
* @param {Buffer} buf
|
||||
*/
|
||||
constructor(buf) {
|
||||
if (!Buffer.isBuffer(buf)) {
|
||||
throw new TypeError('Argument 1 must be an instance of Buffer.');
|
||||
}
|
||||
Object.defineProperty(this, 'buffer', {
|
||||
enumerable: false,
|
||||
value: buf.slice()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {CryptographyKey}
|
||||
*/
|
||||
static from() {
|
||||
return new CryptographyKey(Buffer.from(...arguments));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
isEd25519Key() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
isX25519Key() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
isPublicKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Number}
|
||||
*/
|
||||
getLength() {
|
||||
return this.buffer.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Buffer}
|
||||
*/
|
||||
getBuffer() {
|
||||
return this.buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} encoding
|
||||
*/
|
||||
toString(encoding = 'utf-8') {
|
||||
/* istanbul ignore if */
|
||||
return this.getBuffer().toString(encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Buffer}
|
||||
*/
|
||||
slice() {
|
||||
return this.buffer.slice(...arguments);
|
||||
}
|
||||
};
|
28
library/sodium-plus/lib/keytypes/ed25519pk.js
Normal file
28
library/sodium-plus/lib/keytypes/ed25519pk.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
const CryptographyKey = require('../cryptography-key');
|
||||
|
||||
class Ed25519PublicKey extends CryptographyKey {
|
||||
constructor(buf) {
|
||||
if (buf.length !== 32) {
|
||||
throw new Error('Ed25519 public keys must be 32 bytes long');
|
||||
}
|
||||
super(buf);
|
||||
this.keyType = 'ed25519';
|
||||
this.publicKey = true;
|
||||
}
|
||||
/**
|
||||
* @return {Ed25519PublicKey}
|
||||
*/
|
||||
static from() {
|
||||
return new Ed25519PublicKey(Buffer.from(...arguments));
|
||||
}
|
||||
|
||||
isEd25519Key() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isPublicKey() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ed25519PublicKey;
|
29
library/sodium-plus/lib/keytypes/ed25519sk.js
Normal file
29
library/sodium-plus/lib/keytypes/ed25519sk.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
const CryptographyKey = require('../cryptography-key');
|
||||
|
||||
class Ed25519SecretKey extends CryptographyKey {
|
||||
constructor(buf) {
|
||||
if (buf.length !== 64) {
|
||||
throw new Error('Ed25519 secret keys must be 64 bytes long');
|
||||
}
|
||||
super(buf);
|
||||
this.keyType = 'ed25519';
|
||||
this.publicKey = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {Ed25519SecretKey}
|
||||
*/
|
||||
static from() {
|
||||
return new Ed25519SecretKey(Buffer.from(...arguments));
|
||||
}
|
||||
|
||||
isEd25519Key() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isPublicKey() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ed25519SecretKey;
|
29
library/sodium-plus/lib/keytypes/x25519pk.js
Normal file
29
library/sodium-plus/lib/keytypes/x25519pk.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
const CryptographyKey = require('../cryptography-key');
|
||||
|
||||
class X25519PublicKey extends CryptographyKey {
|
||||
constructor(buf) {
|
||||
if (buf.length !== 32) {
|
||||
throw new Error('X25519 public keys must be 32 bytes long');
|
||||
}
|
||||
super(buf);
|
||||
this.keyType = 'x25519';
|
||||
this.publicKey = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {X25519PublicKey}
|
||||
*/
|
||||
static from() {
|
||||
return new X25519PublicKey(Buffer.from(...arguments));
|
||||
}
|
||||
|
||||
isX25519Key() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isPublicKey() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = X25519PublicKey;
|
29
library/sodium-plus/lib/keytypes/x25519sk.js
Normal file
29
library/sodium-plus/lib/keytypes/x25519sk.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
const CryptographyKey = require('../cryptography-key');
|
||||
|
||||
class X25519SecretKey extends CryptographyKey {
|
||||
constructor(buf) {
|
||||
if (buf.length !== 32) {
|
||||
throw new Error('X25519 secret keys must be 32 bytes long');
|
||||
}
|
||||
super(buf);
|
||||
this.keyType = 'x25519';
|
||||
this.publicKey = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {X25519SecretKey}
|
||||
*/
|
||||
static from() {
|
||||
return new X25519SecretKey(Buffer.from(...arguments));
|
||||
}
|
||||
|
||||
isX25519Key() {
|
||||
return true;
|
||||
}
|
||||
|
||||
isPublicKey() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = X25519SecretKey;
|
74
library/sodium-plus/lib/polyfill.js
Normal file
74
library/sodium-plus/lib/polyfill.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
"use strict";
|
||||
const crypto = require('crypto');
|
||||
const Poly1305 = require('poly1305-js');
|
||||
const Util = require('./util');
|
||||
const XSalsa20 = require('xsalsa20');
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (typeof (Buffer) === 'undefined') {
|
||||
let Buffer = require('buffer/').Buffer;
|
||||
}
|
||||
|
||||
module.exports = class SodiumPolyfill {
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
static async crypto_onetimeauth(message, key) {
|
||||
return Poly1305.onetimeauth(
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} message
|
||||
* @param {CryptographyKey} key
|
||||
* @param {Buffer} tag
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
static async crypto_onetimeauth_verify(message, key, tag) {
|
||||
return Poly1305.onetimeauth_verify(
|
||||
await Util.toBuffer(message),
|
||||
key.getBuffer(),
|
||||
await Util.toBuffer(tag)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string|Buffer} plaintext
|
||||
* @param {Buffer} nonce
|
||||
* @param {CryptographyKey} key
|
||||
* @return {Promise<Buffer>}
|
||||
*/
|
||||
static async crypto_stream_xor(plaintext, nonce, key) {
|
||||
const stream = XSalsa20(nonce, key.getBuffer());
|
||||
const output = stream.update(plaintext);
|
||||
stream.finalize();
|
||||
return Util.toBuffer(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polyfill crypto_pwhash_str_needs_rehash() for bindings that don't
|
||||
* include this (somewhat new) helper function.
|
||||
*
|
||||
* @param {string|Buffer} hash
|
||||
* @param {number} opslimit
|
||||
* @param {number} memlimit
|
||||
* @return {Promise<boolean>}
|
||||
*/
|
||||
static async crypto_pwhash_str_needs_rehash(hash, opslimit, memlimit) {
|
||||
const pwhash = (await Util.toBuffer(hash)).toString('utf-8');
|
||||
const pieces = pwhash.split('$');
|
||||
const expect = 'm=' + (memlimit >> 10) + ',t=' + opslimit + ',p=1';
|
||||
if (expect.length !== pieces[3].length) {
|
||||
return true;
|
||||
}
|
||||
return !crypto.timingSafeEqual(
|
||||
await Util.toBuffer(expect),
|
||||
await Util.toBuffer(pieces[3])
|
||||
);
|
||||
}
|
||||
};
|
1
library/sodium-plus/lib/sodium-error.js
Normal file
1
library/sodium-plus/lib/sodium-error.js
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports = class SodiumError extends Error {};
|
1212
library/sodium-plus/lib/sodiumplus.js
Normal file
1212
library/sodium-plus/lib/sodiumplus.js
Normal file
File diff suppressed because it is too large
Load diff
133
library/sodium-plus/lib/util.js
Normal file
133
library/sodium-plus/lib/util.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
"use strict";
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (typeof (Buffer) === 'undefined') {
|
||||
let Buffer = require('buffer/').Buffer;
|
||||
}
|
||||
|
||||
const arrayToBuffer = require('typedarray-to-buffer');
|
||||
|
||||
module.exports = class Util
|
||||
{
|
||||
static async cloneBuffer(buf) {
|
||||
return Buffer.from(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the sodium constants
|
||||
*
|
||||
* @param {object} anyobject
|
||||
* @return {object}
|
||||
*/
|
||||
static populateConstants(anyobject) {
|
||||
anyobject.LIBRARY_VERSION_MAJOR = 10;
|
||||
anyobject.LIBRARY_VERSION_MINOR = 2;
|
||||
anyobject.VERSION_STRING = '1.0.17';
|
||||
anyobject.BASE64_VARIANT_ORIGINAL = 1;
|
||||
anyobject.BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
|
||||
anyobject.BASE64_VARIANT_URLSAFE = 5;
|
||||
anyobject.BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
|
||||
anyobject.CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
|
||||
anyobject.CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
|
||||
anyobject.CRYPTO_AEAD_AES256GCM_ABYTES = 16;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
|
||||
anyobject.CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
|
||||
anyobject.CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
|
||||
anyobject.CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
|
||||
anyobject.CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
|
||||
anyobject.CRYPTO_AUTH_BYTES = 32;
|
||||
anyobject.CRYPTO_AUTH_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_BOX_SEALBYTES = 16;
|
||||
anyobject.CRYPTO_BOX_SECRETKEYBYTES = 32;
|
||||
anyobject.CRYPTO_BOX_PUBLICKEYBYTES = 32;
|
||||
anyobject.CRYPTO_BOX_KEYPAIRBYTES = 64;
|
||||
anyobject.CRYPTO_BOX_MACBYTES = 16;
|
||||
anyobject.CRYPTO_BOX_NONCEBYTES = 24;
|
||||
anyobject.CRYPTO_BOX_SEEDBYTES = 32;
|
||||
anyobject.CRYPTO_KDF_BYTES_MIN = 16;
|
||||
anyobject.CRYPTO_KDF_BYTES_MAX = 64;
|
||||
anyobject.CRYPTO_KDF_CONTEXTBYTES = 8;
|
||||
anyobject.CRYPTO_KDF_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_KX_BYTES = 32;
|
||||
anyobject.CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
|
||||
anyobject.CRYPTO_KX_SEEDBYTES = 32;
|
||||
anyobject.CRYPTO_KX_KEYPAIRBYTES = 64;
|
||||
anyobject.CRYPTO_KX_PUBLICKEYBYTES = 32;
|
||||
anyobject.CRYPTO_KX_SECRETKEYBYTES = 32;
|
||||
anyobject.CRYPTO_KX_SESSIONKEYBYTES = 32;
|
||||
anyobject.CRYPTO_GENERICHASH_BYTES = 32;
|
||||
anyobject.CRYPTO_GENERICHASH_BYTES_MIN = 16;
|
||||
anyobject.CRYPTO_GENERICHASH_BYTES_MAX = 64;
|
||||
anyobject.CRYPTO_GENERICHASH_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
|
||||
anyobject.CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
|
||||
anyobject.CRYPTO_GENERICHASH_STATEBYTES = 384;
|
||||
anyobject.CRYPTO_PWHASH_SALTBYTES = 16;
|
||||
anyobject.CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
|
||||
anyobject.CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
|
||||
anyobject.CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
|
||||
anyobject.CRYPTO_PWHASH_ALG_DEFAULT = anyobject.CRYPTO_PWHASH_ALG_ARGON2ID13;
|
||||
anyobject.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 2;
|
||||
anyobject.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 67108864;
|
||||
anyobject.CRYPTO_PWHASH_OPSLIMIT_MODERATE = 3;
|
||||
anyobject.CRYPTO_PWHASH_MEMLIMIT_MODERATE = 268435456;
|
||||
anyobject.CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 4;
|
||||
anyobject.CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 1073741824;
|
||||
anyobject.CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
|
||||
anyobject.CRYPTO_SCALARMULT_BYTES = 32;
|
||||
anyobject.CRYPTO_SCALARMULT_SCALARBYTES = 32;
|
||||
anyobject.CRYPTO_SHORTHASH_BYTES = 8;
|
||||
anyobject.CRYPTO_SHORTHASH_KEYBYTES = 16;
|
||||
anyobject.CRYPTO_SECRETBOX_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_SECRETBOX_MACBYTES = 16;
|
||||
anyobject.CRYPTO_SECRETBOX_NONCEBYTES = 24;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_STATEBYTES = 52;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
|
||||
anyobject.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80;
|
||||
anyobject.CRYPTO_SIGN_BYTES = 64;
|
||||
anyobject.CRYPTO_SIGN_SEEDBYTES = 32;
|
||||
anyobject.CRYPTO_SIGN_PUBLICKEYBYTES = 32;
|
||||
anyobject.CRYPTO_SIGN_SECRETKEYBYTES = 64;
|
||||
anyobject.CRYPTO_SIGN_KEYPAIRBYTES = 96;
|
||||
anyobject.CRYPTO_STREAM_KEYBYTES = 32;
|
||||
anyobject.CRYPTO_STREAM_NONCEBYTES = 24;
|
||||
return anyobject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce input to a Buffer, throwing a TypeError if it cannot be coerced.
|
||||
*
|
||||
* @param {string|Buffer|Uint8Array|Promise<Buffer>} stringOrBuffer
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
static async toBuffer(stringOrBuffer)
|
||||
{
|
||||
if (Buffer.isBuffer(stringOrBuffer)) {
|
||||
return stringOrBuffer;
|
||||
} else if (stringOrBuffer === null) {
|
||||
return null;
|
||||
} else if (typeof(stringOrBuffer) === 'string') {
|
||||
return Buffer.from(stringOrBuffer, 'binary');
|
||||
} else if (stringOrBuffer instanceof Uint8Array) {
|
||||
return arrayToBuffer(stringOrBuffer);
|
||||
} else if (stringOrBuffer instanceof Promise) {
|
||||
return await stringOrBuffer;
|
||||
} else {
|
||||
throw new TypeError('Invalid type; string or buffer expected');
|
||||
}
|
||||
}
|
||||
};
|
64
library/sodium-plus/package.json
Normal file
64
library/sodium-plus/package.json
Normal file
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"name": "sodium-plus",
|
||||
"version": "0.9.0",
|
||||
"description": "The Sodium Cryptography Library",
|
||||
"author": "Paragon Initiative Enterprises, LLC",
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"easy-to-use",
|
||||
"libsodium",
|
||||
"sodium",
|
||||
"cryptography",
|
||||
"cryptography library",
|
||||
"elliptic curve cryptography",
|
||||
"ecdh",
|
||||
"eddsa",
|
||||
"diffie-hellman",
|
||||
"authentication",
|
||||
"encryption",
|
||||
"digital signatures",
|
||||
"signatures",
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"x25519",
|
||||
"xsalsa20poly1305",
|
||||
"xchacha20",
|
||||
"poly1305"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"sodium-native": "^3.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"buffer": "^5.6.0",
|
||||
"libsodium-wrappers": "^0.7.6",
|
||||
"poly1305-js": "^0.4.2",
|
||||
"typedarray-to-buffer": "^3.1.5",
|
||||
"xsalsa20": "^1.1.0"
|
||||
},
|
||||
"repository": "https://github.com/paragonie/sodium-plus",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"files": [
|
||||
"build",
|
||||
"build.sh",
|
||||
"dist/sodium-plus.js",
|
||||
"dist/sodium-plus.min.js",
|
||||
"index.d.ts",
|
||||
"index.js",
|
||||
"lib/"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "mocha",
|
||||
"parallel-test": "mocha-parallel-tests"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.0.24",
|
||||
"assert": "^2.0.0",
|
||||
"browserify": "^16.5.1",
|
||||
"chai": "^4.2.0",
|
||||
"mkdirp": "^1.0.4",
|
||||
"mocha-parallel-tests": "^2.3.0",
|
||||
"mocha": "^8.0.1",
|
||||
"tinyify": "^2.5.2"
|
||||
}
|
||||
}
|
13
library/sodium-plus/test/async-helper.js
Normal file
13
library/sodium-plus/test/async-helper.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
const { expect } = require('chai');
|
||||
module.exports = async function expectError(promised, message) {
|
||||
let thrown = false;
|
||||
try {
|
||||
await promised;
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
expect(message).to.be.equal(e.message);
|
||||
}
|
||||
if (!thrown) {
|
||||
throw new Error('Function did not throw');
|
||||
}
|
||||
};
|
37
library/sodium-plus/test/backend-test.js
Normal file
37
library/sodium-plus/test/backend-test.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
const { describe, it } = require('mocha');
|
||||
const { expect } = require('chai');
|
||||
const { SodiumPlus, X25519SecretKey, X25519PublicKey } = require('../index');
|
||||
|
||||
let sodium;
|
||||
describe('Backend', () => {
|
||||
it('crypto_box_keypair_from_secretkey_and_publickey', async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let a = Buffer.alloc(32);
|
||||
let b = Buffer.alloc(32);
|
||||
let c = Buffer.alloc(31);
|
||||
|
||||
let d = await sodium.crypto_box_keypair_from_secretkey_and_publickey(
|
||||
new X25519SecretKey(a),
|
||||
new X25519PublicKey(b)
|
||||
);
|
||||
expect(64).to.be.equal(d.buffer.length);
|
||||
|
||||
expect(() => {
|
||||
sodium.crypto_box_keypair_from_secretkey_and_publickey(
|
||||
new X25519SecretKey(c),
|
||||
new X25519PublicKey(b)
|
||||
)
|
||||
.then(() => {})
|
||||
.catch((e) => { throw e });
|
||||
}).to.throw('X25519 secret keys must be 32 bytes long');
|
||||
|
||||
expect(() => {
|
||||
sodium.crypto_box_keypair_from_secretkey_and_publickey(
|
||||
new X25519SecretKey(a),
|
||||
new X25519PublicKey(c)
|
||||
)
|
||||
.then(() => {})
|
||||
.catch((e) => { throw e });
|
||||
}).to.throw('X25519 public keys must be 32 bytes long');
|
||||
});
|
||||
});
|
83
library/sodium-plus/test/cryptography-key-test.js
Normal file
83
library/sodium-plus/test/cryptography-key-test.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
const assert = require('assert');
|
||||
const crypto = require('crypto');
|
||||
const { describe, it } = require('mocha');
|
||||
const { expect } = require('chai');
|
||||
const {
|
||||
CryptographyKey,
|
||||
Ed25519PublicKey,
|
||||
Ed25519SecretKey,
|
||||
X25519PublicKey,
|
||||
X25519SecretKey
|
||||
} = require('../index');
|
||||
|
||||
let sodium;
|
||||
describe('CryptographyKey', () => {
|
||||
it('Internal buffer is hidden from stack traces and iterators', async () => {
|
||||
let bytes = await crypto.randomBytes(32);
|
||||
let key = new CryptographyKey(bytes);
|
||||
assert(Object.keys(key).length === 0, 'There should be no keys when you dump an object!');
|
||||
expect(bytes.toString('hex')).to.be.equals(key.getBuffer().toString('hex'));
|
||||
expect(bytes.toString('hex')).to.be.equals(key.toString('hex'));
|
||||
});
|
||||
it('constructor rejects invalid types', async () => {
|
||||
let bytes = await crypto.randomBytes(32);
|
||||
let key = new CryptographyKey(bytes);
|
||||
// For test coverage
|
||||
expect(bytes.toString('hex')).to.be.equal(key.slice().toString('hex'));
|
||||
expect(false).to.be.equal(key.isPublicKey());
|
||||
});
|
||||
it('constructor rejects invalid types', () => {
|
||||
expect(() => {
|
||||
new CryptographyKey(new Uint8Array(32))
|
||||
}).to.throw('Argument 1 must be an instance of Buffer.');
|
||||
});
|
||||
|
||||
it('from()', async () => {
|
||||
let key = CryptographyKey.from('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', 'hex');
|
||||
expect(key.getBuffer().toString('hex')).to.be.equals('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f');
|
||||
|
||||
let ed25519sk = Ed25519SecretKey.from(
|
||||
'88c6102ed8b3278ae7e95ebcd4ed3f1a513d2fd3c1a88f5ecbda5f95209ce709' +
|
||||
'324095af3d25e0f205d1a1297d01e810940063d05fc247d2042f6fc2f98a55c2',
|
||||
'hex'
|
||||
);
|
||||
expect(ed25519sk instanceof Ed25519SecretKey).to.be.equals(true);
|
||||
let ed25519pk = Ed25519PublicKey.from(
|
||||
'324095af3d25e0f205d1a1297d01e810940063d05fc247d2042f6fc2f98a55c2',
|
||||
'hex'
|
||||
);
|
||||
expect(ed25519pk instanceof Ed25519PublicKey).to.be.equals(true);
|
||||
let x25519sk = X25519SecretKey.from(
|
||||
'fcb38e648f61e145c96be1a89776754b0a2e28ba57d3024ecae892dc5d93ec26',
|
||||
'hex'
|
||||
);
|
||||
expect(x25519sk instanceof X25519SecretKey).to.be.equals(true);
|
||||
let x25519pk = X25519PublicKey.from(
|
||||
'81149890dc709032327ab8d2628df8c0c8163f59bbb92a6fc3a83cb34864d503',
|
||||
'hex'
|
||||
);
|
||||
expect(x25519pk instanceof X25519PublicKey).to.be.equals(true);
|
||||
|
||||
expect(ed25519sk.isPublicKey()).to.be.equals(false);
|
||||
expect(ed25519pk.isPublicKey()).to.be.equals(true);
|
||||
expect(ed25519sk.isEd25519Key()).to.be.equals(true);
|
||||
expect(ed25519pk.isEd25519Key()).to.be.equals(true);
|
||||
expect(ed25519sk.isX25519Key()).to.be.equals(false);
|
||||
expect(ed25519pk.isX25519Key()).to.be.equals(false);
|
||||
|
||||
expect(x25519sk.isPublicKey()).to.be.equals(false);
|
||||
expect(x25519pk.isPublicKey()).to.be.equals(true);
|
||||
expect(x25519sk.isEd25519Key()).to.be.equals(false);
|
||||
expect(x25519pk.isEd25519Key()).to.be.equals(false);
|
||||
expect(x25519sk.isX25519Key()).to.be.equals(true);
|
||||
expect(x25519pk.isX25519Key()).to.be.equals(true);
|
||||
|
||||
expect(() => {
|
||||
new Ed25519SecretKey(Buffer.alloc(32))
|
||||
}).to.throw('Ed25519 secret keys must be 64 bytes long');
|
||||
|
||||
expect(() => {
|
||||
new Ed25519PublicKey(Buffer.alloc(64))
|
||||
}).to.throw('Ed25519 public keys must be 32 bytes long');
|
||||
});
|
||||
});
|
135
library/sodium-plus/test/longtext.md
Normal file
135
library/sodium-plus/test/longtext.md
Normal file
|
@ -0,0 +1,135 @@
|
|||
<!-- From a blog post -- https://paragonie.com/blog/2019/10/improving-cryptography-javascript-ecosystem -->
|
||||
|
||||
It's been more than eight years since [Javascript Cryptography Considered Harmful](https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful) was published.
|
||||
|
||||
It's just as true today as it was eight years ago that JavaScript cryptography in a web browser is dangerous. **But the *ecosystem* itself has changed immensely in this time.**
|
||||
|
||||
## JavaScript Cryptography, Considered
|
||||
|
||||
Between the continued rise in popularity of JavaScript frameworks (e.g. React) and the prevalence of cross-platform development tools (Cordova, Electron), it's now possible to write JavaScript code once and deploy it on a web server, in a webpage, in a browser extension, in a native mobile app, and in desktop software... with no changes to your JavaScript code.
|
||||
|
||||
Despite eight years of transformative change to the programming landscape, the JavaScript ecosystem has been severely neglected by the security industry, especially with regards to usable cryptography.
|
||||
|
||||
<!--
|
||||
### Putting Skin in the Game
|
||||
|
||||
Anyone who's already familiar with our work knows this already, but we find the security industry's neglect of programming language ecosystems simply *unacceptable*.
|
||||
|
||||
Instead of unhelpful remarks like "Want your code to be secure? Stop writing it in [languages the security industry dislike]", the security industry's responsibility should be to make the languages and tools developers want to use secure.
|
||||
|
||||
This is as true for how Node.js developers are treated by many security experts today as it was for how PHP developers were treated five years ago.
|
||||
|
||||
Unlike most security companies, we're actually putting in the time and work to improve matters. We encourage our colleagues, and challenge our competitors, to step up and do the same (or, at the very least, cease with the gatekeeping remarks).
|
||||
-->
|
||||
|
||||
## What PIE Has Already Done for JavaScript Cryptography
|
||||
|
||||
### Sodium-Plus - A Positive Experience for JS Cryptography
|
||||
|
||||
This month we released [Sodium-Plus](https://github.com/paragonie/sodium-plus), a pluggable, cross-platform, type-safe interface for libsodium to make it easier to write safe and secure JavaScript cryptography code. Our initial announcement was [posted on dev.to](https://dev.to/paragonie/sodium-plus-a-positive-cryptography-experience-for-javascript-developers-2p08).
|
||||
|
||||
To be clear: This isn't a new libsodium binding. What sodium-plus does is wrap one of the existing bindings (e.g. [sodium-native](https://github.com/paragonie/sodium-plus)) and—regardless of how unpleasant the low-level binding's API is to work with—lets you interact with it using a sane and simple asynchronous API.
|
||||
|
||||
Instead of writing code like this:
|
||||
|
||||
<pre><code class="javascript">const sodium = require('sodium-native');
|
||||
|
||||
// Key generation
|
||||
let aliceSecret = Buffer.alloc(32);
|
||||
let alicePublic = Buffer.alloc(32);
|
||||
let bobSecret = Buffer.alloc(32);
|
||||
let bobPublic = Buffer.alloc(32);
|
||||
sodium.crypto_box_keypair(alicePublic, aliceSecret);
|
||||
sodium.crypto_box_keypair(bobPublic, bobSecret);
|
||||
|
||||
// Nonce
|
||||
let nonce = Buffer.alloc(24);
|
||||
sodium.randombytes_buf(nonce);
|
||||
|
||||
// Plaintext
|
||||
let message = 'A string I want to encrypt.';
|
||||
let plaintext = Buffer.from(message);
|
||||
|
||||
// Encrypt
|
||||
let ciphertext = Buffer.alloc(plaintext.length + 16);
|
||||
sodium.crypto_box_easy(ciphertext, plaintext, nonce, bobPublic, aliceSecret);
|
||||
console.log(ciphertext.toString('hex'));
|
||||
|
||||
// Decrypt
|
||||
let decrypted = Buffer.alloc(ciphertext.length - 16);
|
||||
sodium.crypto_box_open_easy(decrypted, ciphertext, nonce, alicePublic, bobSecret);
|
||||
console.log(decrypted.toString());
|
||||
</code></pre>
|
||||
|
||||
...you can just write this:
|
||||
|
||||
<pre><code class="javascript">const { SodiumPlus } = require('sodium-plus');
|
||||
let sodium;
|
||||
|
||||
(async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let aliceKeypair = await sodium.crypto_box_keypair();
|
||||
let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
|
||||
let bobKeypair = await sodium.crypto_box_keypair();
|
||||
let bobSecret = await sodium.crypto_box_secretkey(bobKeypair);
|
||||
let bobPublic = await sodium.crypto_box_publickey(bobKeypair);
|
||||
|
||||
let nonce = await sodium.randombytes_buf(24);
|
||||
let plaintext = 'Your message goes here';
|
||||
let ciphertext = await sodium.crypto_box(plaintext, nonce, aliceSecret, bobPublic);
|
||||
console.log(ciphertext.toString('hex'));
|
||||
|
||||
let decrypted = await sodium.crypto_box_open(ciphertext, nonce, bobSecret, alicePublic);
|
||||
console.log(decrypted.toString());
|
||||
})();
|
||||
</code></pre>
|
||||
|
||||
The second snippet works in browsers, browser extensions, mobile apps, desktop apps, and webservers, without requiring a C compiler be integrated into your JavaScript toolkit.
|
||||
|
||||
By default, Sodium-Plus uses [libsodium-wrappers](https://github.com/jedisct1/libsodium.js). However, if sodium-native is installed, it will opportunistically use that first, since sodium-native offers much better performance.
|
||||
|
||||
One of the many features included in Sodium-Plus is type-safety with cryptography keys. An `Ed25519SecretKey` cannot be used by `crypto_box()`, only by `crypto_sign()`. This prevents a whole host of usage mistakes that passing around bare `Buffer` objects cannot prevent.
|
||||
|
||||
Check out [the Sodium-Plus documentation](https://github.com/paragonie/sodium-plus/tree/master/docs) for more information.
|
||||
|
||||
### Certainty.js: CACert Management for JavaScript Projects
|
||||
|
||||
We originally created [Certainty](https://paragonie.com/blog/2017/10/certainty-automated-cacert-pem-management-for-php-software) to solve the problem of "developers disabling SSL/TLS verification", which was in many cases actually a symptom of the "unreliable/outdated CACert bundle" problem.
|
||||
|
||||
Until recently, there was no congruent means for auto-updating your CACert bundles for Node.js developers. So we decided to write [certainty.js](https://github.com/paragonie/certainty-js).
|
||||
|
||||
<pre><code class="javascript">const {Certainty} = require('certainty-js');
|
||||
const http = require('request-promise-native');
|
||||
|
||||
(async function () {
|
||||
let options = {
|
||||
'ca': await Certainty.getLatestCABundle('/path/to/directory'),
|
||||
'uri': 'https://php-chronicle.pie-hosted.com/chronicle/lasthash',
|
||||
'minVersion': 'TLSv1.2',
|
||||
'strictSSL': true,
|
||||
'timeout': 30000
|
||||
};
|
||||
|
||||
// Send request...
|
||||
console.log(await http.get(options));
|
||||
})();</code></pre>
|
||||
|
||||
The next releases of Certainty.js will include the LocalCACertBuilder features from the PHP version, as well as a refactor to use `Sodium-Plus`.
|
||||
|
||||
### CipherSweet.js
|
||||
|
||||
Scenario: You need to encrypt some of your database fields, but you still need to use those fields in SELECT queries somehow. Is there a secure way to achieve this result without having to invoke a lot of new and experimental cryptography primitives?
|
||||
|
||||
It turns out: Yes, you can. Our proposed implementation is called [CipherSweet](https://paragonie.com/blog/2019/01/ciphersweet-searchable-encryption-doesn-t-have-be-bitter).
|
||||
|
||||
CipherSweet has already been ported from PHP to Node.js, with other languages coming soon.
|
||||
|
||||
You can find [CipherSweet-js](https://github.com/paragonie/ciphersweet-js) on Github. The documentation is available [on our website](https://ciphersweet.paragonie.com/node.js).
|
||||
|
||||
## Our Work Continues
|
||||
|
||||
Like many other programming languages, JavaScript has its own needs and unique challenges. We
|
||||
remain committed to improving the security and usability of the languages, frameworks, and tools developers want to use, and strive towards a more private and secure Internet for everyone.
|
||||
|
||||
If your company relies on PHP or JavaScript code and needs expert assistance with solving cryptography problems in your application, [reach out to us](https://paragonie.com/contact). We [write code](https://paragonie.com/service/app-dev), [audit code](https://paragonie.com/service/code-review), and [offer consultation for security designs](https://paragonie.com/service/technology-consulting).
|
33
library/sodium-plus/test/sodiumplus-pwhash-test.js
Normal file
33
library/sodium-plus/test/sodiumplus-pwhash-test.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
const { describe, it } = require('mocha');
|
||||
const { expect } = require('chai');
|
||||
const { SodiumPlus } = require('../index');
|
||||
const VERBOSE = false;
|
||||
|
||||
let sodium;
|
||||
|
||||
(async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
if (VERBOSE) {
|
||||
console.log({
|
||||
'libsodium-wrappers': sodium.isLibsodiumWrappers(),
|
||||
'sodium-native': sodium.isSodiumNative()
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
describe('SodiumPlus', () => {
|
||||
it('crypto_pwhash', async function() {
|
||||
this.timeout(0);
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let password = 'correct horse battery staple';
|
||||
let salt = Buffer.from('808182838485868788898a8b8c8d8e8f', 'hex');
|
||||
let hashed = await sodium.crypto_pwhash(
|
||||
16,
|
||||
password,
|
||||
salt,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
|
||||
);
|
||||
expect(hashed.toString('hex')).to.be.equals('720f95400220748a811bca9b8cff5d6e');
|
||||
});
|
||||
});
|
53
library/sodium-plus/test/sodiumplus-pwhashstr-test.js
Normal file
53
library/sodium-plus/test/sodiumplus-pwhashstr-test.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
const assert = require('assert');
|
||||
const { describe, it } = require('mocha');
|
||||
const { expect } = require('chai');
|
||||
const { SodiumPlus } = require('../index');
|
||||
const VERBOSE = false;
|
||||
|
||||
let sodium;
|
||||
|
||||
(async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
if (VERBOSE) {
|
||||
console.log({
|
||||
'libsodium-wrappers': sodium.isLibsodiumWrappers(),
|
||||
'sodium-native': sodium.isSodiumNative()
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
describe('SodiumPlus', () => {
|
||||
it('SodiumPlus.crypto_pwhash_str', async function () {
|
||||
this.timeout(0);
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let password = 'correct horse battery staple';
|
||||
let hashed = await sodium.crypto_pwhash_str(
|
||||
password,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
|
||||
);
|
||||
assert(hashed);
|
||||
assert(await sodium.crypto_pwhash_str_verify(password, hashed));
|
||||
assert(await sodium.crypto_pwhash_str_verify('incorrect password', hashed) === false);
|
||||
|
||||
let needs;
|
||||
needs = await sodium.crypto_pwhash_str_needs_rehash(
|
||||
hashed,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
|
||||
);
|
||||
expect(needs).to.be.equals(false);
|
||||
needs = await sodium.crypto_pwhash_str_needs_rehash(
|
||||
hashed,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE + 1,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
|
||||
);
|
||||
expect(needs).to.be.equals(true);
|
||||
needs = await sodium.crypto_pwhash_str_needs_rehash(
|
||||
hashed,
|
||||
sodium.CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
|
||||
sodium.CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE << 1
|
||||
);
|
||||
expect(needs).to.be.equals(true);
|
||||
});
|
||||
});
|
732
library/sodium-plus/test/sodiumplus-test.js
Normal file
732
library/sodium-plus/test/sodiumplus-test.js
Normal file
|
@ -0,0 +1,732 @@
|
|||
const assert = require('assert');
|
||||
const expectError = require('./async-helper');
|
||||
const fsp = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { describe, it } = require('mocha');
|
||||
const { expect } = require('chai');
|
||||
const { CryptographyKey, SodiumPlus, X25519PublicKey, X25519SecretKey } = require('../index');
|
||||
const Util = require('../lib/util');
|
||||
const VERBOSE = false;
|
||||
|
||||
let sodium;
|
||||
|
||||
(async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
if (VERBOSE) {
|
||||
console.log({
|
||||
'libsodium-wrappers': sodium.isLibsodiumWrappers(),
|
||||
'sodium-native': sodium.isSodiumNative()
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
describe('SodiumPlus', () => {
|
||||
it('ensureLoaded', async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
await sodium.ensureLoaded();
|
||||
expect('string').to.be.equal(typeof sodium.getBackendName());
|
||||
expect('boolean').to.be.equal(typeof sodium.isSodiumNative());
|
||||
expect('boolean').to.be.equal(typeof sodium.isLibsodiumWrappers());
|
||||
});
|
||||
|
||||
it('index.js', async () => {
|
||||
const indexFile = require('../index');
|
||||
expect(typeof indexFile.getBackendObject()).to.be.equal('function');
|
||||
expect(typeof indexFile.getBackendObject('SodiumNative')).to.be.equal('function');
|
||||
expect(typeof indexFile.getBackendObject('LibsodiumWrappers')).to.be.equal('function');
|
||||
expect(() => {
|
||||
indexFile.getBackendObject('Sodium')
|
||||
}).to.throw('Unrecognized backend type: Sodium');
|
||||
});
|
||||
|
||||
it('SodiumPlus.CONSTANTS', async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let dummy = Util.populateConstants({});
|
||||
for (let val in dummy) {
|
||||
expect(sodium.backend[val]).to.be.equals(dummy[val]);
|
||||
expect(sodium[val]).to.be.equals(dummy[val]);
|
||||
}
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_aead_xchacha20poly1305_ietf_*', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = Buffer.from(
|
||||
'4c616469657320616e642047656e746c656d656e206f662074686520636c6173' +
|
||||
'73206f66202739393a204966204920636f756c64206f6666657220796f75206f' +
|
||||
'6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73' +
|
||||
'637265656e20776f756c642062652069742e',
|
||||
'hex'
|
||||
);
|
||||
let assocData = Buffer.from('50515253c0c1c2c3c4c5c6c7', 'hex');
|
||||
let nonce = Buffer.from('404142434445464748494a4b4c4d4e4f5051525354555657', 'hex');
|
||||
let key = CryptographyKey.from('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', 'hex');
|
||||
|
||||
let ciphertext = await sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, nonce, key, assocData);
|
||||
|
||||
let expected = 'bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb' +
|
||||
'731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b452' +
|
||||
'2f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff9' +
|
||||
'21f9664c97637da9768812f615c68b13b52e' +
|
||||
'c0875924c1c7987947deafd8780acf49';
|
||||
expect(ciphertext.toString('hex')).to.be.equals(expected);
|
||||
|
||||
let decrypted = await sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(ciphertext, nonce, key, assocData);
|
||||
expect(decrypted.toString('hex')).to.be.equals(plaintext.toString('hex'));
|
||||
|
||||
let randomKey = await sodium.crypto_aead_xchacha20poly1305_ietf_keygen();
|
||||
assert(randomKey instanceof CryptographyKey);
|
||||
|
||||
let ciphertext2 = await sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, nonce, randomKey);
|
||||
decrypted = await sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(ciphertext2, nonce, randomKey);
|
||||
expect(decrypted.toString('hex')).to.be.equals(plaintext.toString('hex'));
|
||||
expect(ciphertext.toString('hex')).to.not.equals(ciphertext2.toString('hex'));
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(plaintext, nonce.slice(1), randomKey),
|
||||
'Argument 2 must be 24 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(plaintext, nonce, Buffer.alloc(32)),
|
||||
'Argument 3 must be an instance of CryptographyKey'
|
||||
);
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, nonce.slice(1), randomKey),
|
||||
'Argument 2 must be 24 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, nonce, Buffer.alloc(32)),
|
||||
'Argument 3 must be an instance of CryptographyKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_auth', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let key = await sodium.crypto_auth_keygen();
|
||||
let message = 'Science, math, technology, engineering, and compassion for others.';
|
||||
let mac = await sodium.crypto_auth(message, key);
|
||||
assert(await sodium.crypto_auth_verify(message, key, mac) === true);
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_auth(message, Buffer.alloc(32)),
|
||||
'Argument 2 must be an instance of CryptographyKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_auth_verify(message, Buffer.alloc(32), mac),
|
||||
'Argument 2 must be an instance of CryptographyKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_box', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = 'Science, math, technology, engineering, and compassion for others.';
|
||||
|
||||
let aliceKeypair = await sodium.crypto_box_keypair();
|
||||
let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
|
||||
|
||||
let bobKeypair = await sodium.crypto_box_keypair();
|
||||
let bobSecret = await sodium.crypto_box_secretkey(bobKeypair);
|
||||
let bobPublic = await sodium.crypto_box_publickey(bobKeypair);
|
||||
|
||||
let nonce = await sodium.randombytes_buf(24);
|
||||
|
||||
let ciphertext = await sodium.crypto_box(plaintext, nonce, aliceSecret, bobPublic);
|
||||
let decrypted = await sodium.crypto_box_open(ciphertext, nonce, bobSecret, alicePublic);
|
||||
expect(decrypted.toString('hex')).to.be.equals(Buffer.from(plaintext).toString('hex'));
|
||||
|
||||
let derived = await sodium.crypto_box_publickey_from_secretkey(aliceSecret);
|
||||
expect(alicePublic.getBuffer().toString('hex'))
|
||||
.to.be.equal(derived.getBuffer().toString('hex'));
|
||||
|
||||
/* Unhappy path: */
|
||||
await expectError(
|
||||
sodium.crypto_box(plaintext, nonce, alicePublic, bobPublic),
|
||||
'Argument 3 must be an instance of X25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box(plaintext, nonce, bobSecret, aliceSecret),
|
||||
'Argument 4 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box(plaintext, nonce.slice(1), bobSecret, alicePublic),
|
||||
'Nonce must be a buffer of exactly 24 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_open(ciphertext, nonce, alicePublic, bobPublic),
|
||||
'Argument 3 must be an instance of X25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_open(ciphertext, nonce, bobSecret, aliceSecret),
|
||||
'Argument 4 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_open(ciphertext.slice(0, 14), nonce, bobSecret, alicePublic),
|
||||
'Ciphertext must be a buffer of at least 16 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_open(ciphertext, nonce.slice(1), bobSecret, alicePublic),
|
||||
'Nonce must be a buffer of exactly 24 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_keypair_from_secretkey_and_publickey(alicePublic, alicePublic),
|
||||
'Argument 1 must be an instance of X25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_keypair_from_secretkey_and_publickey(aliceSecret, aliceSecret),
|
||||
'Argument 2 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_secretkey(derived),
|
||||
'Keypair must be 64 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_publickey(derived),
|
||||
'Keypair must be 64 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_publickey_from_secretkey(derived),
|
||||
'Argument 1 must be an instance of X25519SecretKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_box_seal', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = 'Science, math, technology, engineering, and compassion for others.';
|
||||
|
||||
let aliceKeypair = await sodium.crypto_box_keypair();
|
||||
let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
|
||||
assert(aliceSecret instanceof X25519SecretKey);
|
||||
assert(alicePublic instanceof X25519PublicKey);
|
||||
|
||||
let ciphertext = await sodium.crypto_box_seal(plaintext, alicePublic);
|
||||
let decrypted = await sodium.crypto_box_seal_open(ciphertext, alicePublic, aliceSecret);
|
||||
expect(decrypted.toString('hex')).to.be.equals(Buffer.from(plaintext).toString('hex'));
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_box_seal(plaintext, aliceSecret),
|
||||
'Argument 2 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_seal_open(plaintext, aliceSecret, aliceSecret),
|
||||
'Argument 2 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_box_seal_open(plaintext, alicePublic, alicePublic),
|
||||
'Argument 3 must be an instance of X25519SecretKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_generichash', async() => {
|
||||
let message = 'Science, math, technology, engineering, and compassion for others.';
|
||||
let piece1 = message.slice(0, 16);
|
||||
let piece2 = message.slice(16);
|
||||
|
||||
let hash1 = await sodium.crypto_generichash(message);
|
||||
expect(hash1.toString('hex')).to.be.equals('47c1fdbde32b30b9c54dd47cf88ba92d2d05df1265e342c9563ed56aee84ab02');
|
||||
|
||||
let state = await sodium.crypto_generichash_init();
|
||||
await sodium.crypto_generichash_update(state, piece1);
|
||||
await sodium.crypto_generichash_update(state, piece2);
|
||||
let hash2 = await sodium.crypto_generichash_final(state);
|
||||
expect(hash1.toString('hex')).to.be.equals(hash2.toString('hex'));
|
||||
|
||||
let key = await sodium.crypto_generichash_keygen();
|
||||
hash1 = await sodium.crypto_generichash(message, key);
|
||||
state = await sodium.crypto_generichash_init(key);
|
||||
await sodium.crypto_generichash_update(state, piece1);
|
||||
await sodium.crypto_generichash_update(state, piece2);
|
||||
hash2 = await sodium.crypto_generichash_final(state);
|
||||
expect(hash1.toString('hex')).to.be.equals(hash2.toString('hex'));
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_kdf', async function() {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let subkey, expected;
|
||||
let key = CryptographyKey.from('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f', 'hex');
|
||||
let context = 'NaClTest';
|
||||
subkey = await sodium.crypto_kdf_derive_from_key(32, 1, context, key);
|
||||
expected = 'bce6fcf118cac2691bb23975a63dfac02282c1cd5de6ab9febcbb0ec4348181b';
|
||||
expect(subkey.toString('hex')).to.be.equals(expected);
|
||||
|
||||
subkey = await sodium.crypto_kdf_derive_from_key(32, 2, context, key);
|
||||
expected = '877cf1c1a2da9b900c79464acebc3731ed4ebe326a7951911639821d09dc6dda';
|
||||
expect(subkey.toString('hex')).to.be.equals(expected);
|
||||
|
||||
let key2 = await sodium.crypto_kdf_keygen();
|
||||
let subkey2 = await sodium.crypto_kdf_derive_from_key(32, 1, context, key2);
|
||||
expect(subkey2.toString('hex')).to.not.equals(key2.toString('hex'));
|
||||
expect(subkey2.toString('hex')).to.not.equals(subkey.toString('hex'));
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_kdf_derive_from_key(-32, 1, context, key2),
|
||||
'Length must be a positive integer.'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_kdf_derive_from_key(32, -1, context, key2),
|
||||
'Key ID must be an unsigned integer'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_kx', async function() {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let clientKeys = await sodium.crypto_kx_keypair();
|
||||
let clientSecret = await sodium.crypto_box_secretkey(clientKeys);
|
||||
let clientPublic = await sodium.crypto_box_publickey(clientKeys);
|
||||
let seed = 'Unit test static key seed goes here. Nothing too complicated. No randomness needed, really.';
|
||||
let serverKeys = await sodium.crypto_kx_seed_keypair(seed);
|
||||
let serverSecret = await sodium.crypto_box_secretkey(serverKeys);
|
||||
let serverPublic = await sodium.crypto_box_publickey(serverKeys);
|
||||
let clientRx, clientTx, serverRx, serverTx;
|
||||
|
||||
[clientRx, clientTx] = await sodium.crypto_kx_client_session_keys(clientPublic, clientSecret, serverPublic);
|
||||
[serverRx, serverTx] = await sodium.crypto_kx_server_session_keys(serverPublic, serverSecret, clientPublic);
|
||||
|
||||
expect(clientRx.toString('hex')).to.be.equals(serverTx.toString('hex'));
|
||||
expect(clientTx.toString('hex')).to.be.equals(serverRx.toString('hex'));
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_kx_client_session_keys(clientSecret, clientSecret, serverPublic),
|
||||
'Argument 1 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_kx_client_session_keys(clientPublic, clientPublic, serverPublic),
|
||||
'Argument 2 must be an instance of X25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_kx_client_session_keys(clientPublic, clientSecret, serverSecret),
|
||||
'Argument 3 must be an instance of X25519PublicKey'
|
||||
);
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_kx_server_session_keys(serverSecret, serverSecret, clientPublic),
|
||||
'Argument 1 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_kx_server_session_keys(serverPublic, serverPublic, clientPublic),
|
||||
'Argument 2 must be an instance of X25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_kx_server_session_keys(serverPublic, serverSecret, clientSecret),
|
||||
'Argument 3 must be an instance of X25519PublicKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_onetimeauth', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let key = await sodium.crypto_onetimeauth_keygen();
|
||||
let plaintext = 'Science, math, technology, engineering, and compassion for others.';
|
||||
let tag = await sodium.crypto_onetimeauth(plaintext, key);
|
||||
assert(await sodium.crypto_onetimeauth_verify(plaintext, key, tag));
|
||||
assert((await sodium.crypto_onetimeauth_verify(plaintext + ' extra', key, tag)) === false);
|
||||
|
||||
let msg = Buffer.alloc(32, 0);
|
||||
key = CryptographyKey.from('746869732069732033322d62797465206b657920666f7220506f6c7931333035', 'hex');
|
||||
tag = await sodium.crypto_onetimeauth(msg, key);
|
||||
expect(tag.toString('hex')).to.be.equals('49ec78090e481ec6c26b33b91ccc0307');
|
||||
assert(await sodium.crypto_onetimeauth_verify(msg, key, tag));
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_onetimeauth(msg, Buffer.alloc(32)),
|
||||
'Argument 2 must be an instance of CryptographyKey'
|
||||
);
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_onetimeauth_verify(msg, Buffer.alloc(32), tag),
|
||||
'Argument 2 must be an instance of CryptographyKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_scalarmult', async() => {
|
||||
let aliceKeypair = await sodium.crypto_box_keypair();
|
||||
let aliceSecret = await sodium.crypto_box_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_box_publickey(aliceKeypair);
|
||||
assert(aliceSecret instanceof X25519SecretKey);
|
||||
assert(alicePublic instanceof X25519PublicKey);
|
||||
|
||||
// crypto_scalarmult_base test:
|
||||
let testPublic = await sodium.crypto_scalarmult_base(aliceSecret);
|
||||
expect(testPublic.getBuffer().toString('hex')).to.be.equals(alicePublic.getBuffer().toString('hex'));
|
||||
|
||||
// crypto_scalarmult test:
|
||||
let bobKeypair = await sodium.crypto_box_keypair();
|
||||
let bobSecret = await sodium.crypto_box_secretkey(bobKeypair);
|
||||
let bobPublic = await sodium.crypto_box_publickey(bobKeypair);
|
||||
|
||||
expect(alicePublic.getBuffer().toString('hex')).to.be.equals(alicePublic.getBuffer().toString('hex'));
|
||||
|
||||
let ab = await sodium.crypto_scalarmult(aliceSecret, bobPublic);
|
||||
expect(ab.toString('hex')).to.not.equals('0000000000000000000000000000000000000000000000000000000000000000');
|
||||
let ba = await sodium.crypto_scalarmult(bobSecret, alicePublic);
|
||||
expect(ba.toString('hex')).to.not.equals('0000000000000000000000000000000000000000000000000000000000000000');
|
||||
expect(ab.toString('hex')).to.be.equals(ba.toString('hex'));
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_scalarmult(alicePublic, bobPublic),
|
||||
'Argument 1 must be an instance of X25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_scalarmult(aliceSecret, bobSecret),
|
||||
'Argument 2 must be an instance of X25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_scalarmult_base(alicePublic),
|
||||
'Argument 1 must be an instance of X25519SecretKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_secretbox', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let plaintext = 'Science, math, technology, engineering, and compassion for others.';
|
||||
|
||||
let key = await sodium.crypto_secretbox_keygen();
|
||||
let nonce = await sodium.randombytes_buf(24);
|
||||
|
||||
let ciphertext = await sodium.crypto_secretbox(plaintext, nonce, key);
|
||||
let decrypted = await sodium.crypto_secretbox_open(ciphertext, nonce, key);
|
||||
expect(decrypted.toString('hex')).to.be.equals(Buffer.from(plaintext).toString('hex'));
|
||||
|
||||
// Unhappy path:
|
||||
let ed25519key = await sodium.crypto_sign_secretkey(await sodium.crypto_sign_keypair());
|
||||
await expectError(
|
||||
sodium.crypto_secretbox(ciphertext.slice(0, 14), nonce, ed25519key),
|
||||
'Argument 3 must not be an asymmetric key'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_secretbox(ciphertext, nonce.slice(1), key),
|
||||
'Nonce must be a buffer of exactly 24 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_secretbox_open(ciphertext.slice(0, 14), nonce, ed25519key),
|
||||
'Argument 3 must not be an asymmetric key'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_secretbox_open(ciphertext.slice(0, 14), nonce, key),
|
||||
'Ciphertext must be a buffer of at least 16 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_secretbox_open(ciphertext, nonce.slice(1), key),
|
||||
'Nonce must be a buffer of exactly 24 bytes'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_secretstream_xchacha20poly1305', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
let key = await sodium.crypto_secretstream_xchacha20poly1305_keygen();
|
||||
let encryptor, decryptor;
|
||||
encryptor = await sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
|
||||
decryptor = await sodium.crypto_secretstream_xchacha20poly1305_init_pull(key, encryptor.header);
|
||||
|
||||
await expectError(
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_push(Buffer.alloc(31)),
|
||||
'Key must be an instance of CryptographyKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_pull(Buffer.alloc(31), encryptor.header),
|
||||
'Key must be an instance of CryptographyKey'
|
||||
);
|
||||
|
||||
let invalidKey = new CryptographyKey(Buffer.alloc(31));
|
||||
await expectError(
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_push(invalidKey),
|
||||
'crypto_secretstream keys must be 32 bytes long'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_pull(invalidKey, encryptor.header),
|
||||
'crypto_secretstream keys must be 32 bytes long'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_secretstream_xchacha20poly1305_init_pull(key, encryptor.header.slice(1)),
|
||||
'crypto_secretstream headers must be 24 bytes long'
|
||||
);
|
||||
|
||||
// Get a test input from the text file.
|
||||
let longText = await fsp.readFile(path.join(__dirname, 'longtext.md'));
|
||||
let chunk, readUntil;
|
||||
let ciphertext = Buffer.concat([encryptor.header]);
|
||||
|
||||
// How big are our chunks going to be?
|
||||
let PUSH_CHUNK_SIZE = await sodium.randombytes_uniform(longText.length - 32) + 32;
|
||||
let PULL_CHUNK_SIZE = PUSH_CHUNK_SIZE + sodium.CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
|
||||
|
||||
// Encrypt
|
||||
for (let i = 0; i < longText.length; i += PUSH_CHUNK_SIZE) {
|
||||
readUntil = (i + PUSH_CHUNK_SIZE) > longText.length ? longText.length : i + PUSH_CHUNK_SIZE;
|
||||
chunk = await encryptor.push(
|
||||
longText.slice(i, readUntil)
|
||||
);
|
||||
ciphertext = Buffer.concat([ciphertext, chunk]);
|
||||
}
|
||||
expect(ciphertext.slice(0, 24).toString('hex')).to.be
|
||||
.equals(encryptor.header.toString('hex'));
|
||||
|
||||
// Decrypt, starting at 24 (after the header, which we already have)
|
||||
let decrypted = Buffer.alloc(0);
|
||||
for (let i = 24; i < ciphertext.length; i += PULL_CHUNK_SIZE) {
|
||||
readUntil = (i + PULL_CHUNK_SIZE) > ciphertext.length ? ciphertext.length : i + PULL_CHUNK_SIZE;
|
||||
chunk = await decryptor.pull(
|
||||
ciphertext.slice(i, readUntil)
|
||||
);
|
||||
decrypted = Buffer.concat([decrypted, chunk]);
|
||||
}
|
||||
expect(decrypted.toString('hex')).to.be.equals(longText.toString('hex'));
|
||||
await encryptor.rekey();
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_shorthash', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let key = CryptographyKey.from('808182838485868788898a8b8c8d8e8f', 'hex');
|
||||
let message;
|
||||
let hash;
|
||||
|
||||
message = 'This is short input0';
|
||||
hash = await sodium.crypto_shorthash(message, key);
|
||||
expect(hash.toString('hex')).to.be.equals('ef589fb9ef4196b3');
|
||||
|
||||
message = 'This is short input1';
|
||||
hash = await sodium.crypto_shorthash(message, key);
|
||||
expect(hash.toString('hex')).to.be.equals('5e8f01039bc53eb7');
|
||||
|
||||
let random = await sodium.crypto_shorthash_keygen();
|
||||
expect(sodium.CRYPTO_SHORTHASH_KEYBYTES).to.be.equal(random.getLength());
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_sign_seed_keypair', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let aliceKeypair = await sodium.crypto_sign_seed_keypair(
|
||||
await sodium.crypto_generichash('sodium-plus')
|
||||
);
|
||||
let alicePublic = await sodium.crypto_sign_publickey(aliceKeypair);
|
||||
expect(alicePublic.getBuffer().toString('hex')).to.be.equals(
|
||||
'292288efba3a33275d216f2e4d9014d330f3b2852d6b767de15e43839096d6e8'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_sign_seed_keypair(Buffer.alloc(31)),
|
||||
'Seed must be 32 bytes long; got 31'
|
||||
);
|
||||
// Should not throw:
|
||||
await sodium.crypto_sign_seed_keypair(
|
||||
new CryptographyKey(await sodium.crypto_generichash('sodium-plus'))
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_sign_{secret,public}key', async() => {
|
||||
await expectError(
|
||||
sodium.crypto_sign_secretkey(new CryptographyKey(Buffer.alloc(16))),
|
||||
'Keypair must be 96 bytes'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_sign_publickey(new CryptographyKey(Buffer.alloc(16))),
|
||||
'Keypair must be 96 bytes'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_sign', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let aliceKeypair = await sodium.crypto_sign_keypair();
|
||||
let aliceSecret = await sodium.crypto_sign_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_sign_publickey(aliceKeypair);
|
||||
|
||||
let plaintext = 'Science, math, technology, engineering, and compassion for others.';
|
||||
let signed = await sodium.crypto_sign(plaintext, aliceSecret);
|
||||
let opened = await sodium.crypto_sign_open(signed, alicePublic);
|
||||
expect(signed.slice(64).toString('hex')).to.be.equals(opened.toString('hex'));
|
||||
expect(opened.toString()).to.be.equals(plaintext);
|
||||
|
||||
let signature = await sodium.crypto_sign_detached(plaintext, aliceSecret);
|
||||
let valid = await sodium.crypto_sign_verify_detached(plaintext, alicePublic, signature);
|
||||
expect(valid).to.be.equals(true);
|
||||
let invalid = await sodium.crypto_sign_verify_detached(plaintext + ' extra', alicePublic, signature);
|
||||
expect(invalid).to.be.equals(false);
|
||||
await expectError(
|
||||
sodium.crypto_sign(plaintext, alicePublic),
|
||||
'Argument 2 must be an instance of Ed25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_sign_open(signed, aliceSecret),
|
||||
'Argument 2 must be an instance of Ed25519PublicKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_sign_detached(plaintext, alicePublic),
|
||||
'Argument 2 must be an instance of Ed25519SecretKey'
|
||||
);
|
||||
await expectError(
|
||||
sodium.crypto_sign_verify_detached(plaintext, aliceSecret, signature),
|
||||
'Argument 2 must be an instance of Ed25519PublicKey'
|
||||
);
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_sign_ed25519_to_curve25519', async function () {
|
||||
this.timeout(0);
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
let aliceKeypair = CryptographyKey.from(
|
||||
'411a2c2227d2a799ebae0ed94417d8e8ed1ca9b0a9d5f4cd743cc52d961e94e2' +
|
||||
'da49154c9e700b754199df7974e9fa4ee4b6ebbc71f89d8d8938335ea4a1409d' +
|
||||
'da49154c9e700b754199df7974e9fa4ee4b6ebbc71f89d8d8938335ea4a1409d', 'hex');
|
||||
let aliceSecret = await sodium.crypto_sign_secretkey(aliceKeypair);
|
||||
let alicePublic = await sodium.crypto_sign_publickey(aliceKeypair);
|
||||
|
||||
let ecdhSecret = await sodium.crypto_sign_ed25519_sk_to_curve25519(aliceSecret);
|
||||
expect(ecdhSecret.toString('hex')).to.be
|
||||
.equals('60c783b8d1674b7081b72a105b55872502825d4ec638028152e085b54705ad7e');
|
||||
let ecdhPublic = await sodium.crypto_sign_ed25519_pk_to_curve25519(alicePublic);
|
||||
expect(ecdhPublic.toString('hex')).to.be
|
||||
.equals('5a791d07cfb39060c8e9b641b6a915a3126cd14ddc243a9928c490c8e1f59e7c');
|
||||
});
|
||||
|
||||
it('SodiumPlus.crypto_stream', async function () {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let key = CryptographyKey.from('8000000000000000000000000000000000000000000000000000000000000000', 'hex');
|
||||
let iv = Buffer.alloc(24, 0);
|
||||
let output = await sodium.crypto_stream(256, iv, key);
|
||||
let testVector = '93D88C085B8433B1FBAD2221FAD718078D96119F727D27F0547F9F3D29DE1358' +
|
||||
'F3FE3D9EEACF59E894FA76E6507F567B4A0796DD00D8BFC736344A9906CB1F5D';
|
||||
expect(output.slice(0, 64).toString('hex').toUpperCase()).to.be.equals(testVector);
|
||||
testVector = '17FD2BD86D095016D8367E0DD47D3E4A18DAE7BB24F8B5E3E9F52C4A493BE982' +
|
||||
'ECA8E89A4DEC78467E31087A1ACDA83754BEFB273AB27EB396EB4957F7166C25';
|
||||
expect(output.slice(192, 256).toString('hex').toUpperCase()).to.be.equals(testVector);
|
||||
|
||||
key = CryptographyKey.from('8080808080808080808080808080808080808080808080808080808080808080', 'hex');
|
||||
output = await sodium.crypto_stream_xor('Test message', iv, key);
|
||||
expect(output.toString('hex')).to.be.equals('1071d0355cb22c4c4e00303f');
|
||||
|
||||
key = await sodium.crypto_stream_keygen();
|
||||
iv = await sodium.randombytes_buf(24);
|
||||
let plaintext = 'This is a secret message';
|
||||
let ciphertext = await sodium.crypto_stream_xor(plaintext, iv, key);
|
||||
let decrypted = await sodium.crypto_stream_xor(ciphertext, iv, key);
|
||||
expect(decrypted.toString()).to.be.equals(plaintext);
|
||||
});
|
||||
|
||||
it('SodiumPlus.randombytes_buf', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let a, b;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
a = await sodium.randombytes_buf(64);
|
||||
b = await sodium.randombytes_buf(64);
|
||||
expect(a.toString('hex')).to.not.equals(b.toString('hex'));
|
||||
}
|
||||
});
|
||||
|
||||
it('SodiumPlus.randombytes_uniform', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let a, b;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
a = await sodium.randombytes_uniform(0x3fffffff);
|
||||
b = await sodium.randombytes_uniform(0x3fffffff);
|
||||
expect(a).to.not.equals(b);
|
||||
}
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_bin2hex', async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let buf = await sodium.randombytes_buf(32);
|
||||
|
||||
expect(await sodium.sodium_bin2hex(buf)).to.be.equals(buf.toString('hex'));
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_add', async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let foo = Buffer.from('ed000000', 'hex');
|
||||
let bar = Buffer.from('01000000', 'hex');
|
||||
let baz = await sodium.sodium_add(foo, bar);
|
||||
expect(baz.toString('hex')).to.be.equals('ee000000');
|
||||
|
||||
bar = Buffer.from('ff000000', 'hex');
|
||||
baz = await sodium.sodium_add(baz, bar);
|
||||
expect(baz.toString('hex')).to.be.equals('ed010000');
|
||||
|
||||
foo = Buffer.from('ffffffff', 'hex');
|
||||
bar = Buffer.from('01000000', 'hex');
|
||||
baz = await sodium.sodium_add(foo, bar);
|
||||
expect(baz.toString('hex')).to.be.equals('00000000');
|
||||
bar = Buffer.from('02000000', 'hex');
|
||||
baz = await sodium.sodium_add(foo, bar);
|
||||
expect(baz.toString('hex')).to.be.equals('01000000');
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_compare', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let a = Buffer.from('80808080', 'hex');
|
||||
let b = Buffer.from('81808080', 'hex');
|
||||
let c = Buffer.from('80808081', 'hex');
|
||||
|
||||
expect(await sodium.sodium_compare(a, a)).to.be.equals(0);
|
||||
expect(await sodium.sodium_compare(b, b)).to.be.equals(0);
|
||||
expect(await sodium.sodium_compare(c, c)).to.be.equals(0);
|
||||
expect(await sodium.sodium_compare(a, b)).to.be.below(0);
|
||||
expect(await sodium.sodium_compare(b, a)).to.be.above(0);
|
||||
expect(await sodium.sodium_compare(a, c)).to.be.below(0);
|
||||
expect(await sodium.sodium_compare(c, a)).to.be.above(0);
|
||||
expect(await sodium.sodium_compare(b, c)).to.be.below(0);
|
||||
expect(await sodium.sodium_compare(c, b)).to.be.above(0);
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_hex2bin', async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let buf = await sodium.randombytes_buf(32);
|
||||
let hex = buf.toString('hex');
|
||||
let bin = await sodium.sodium_hex2bin(hex);
|
||||
expect(Buffer.isBuffer(bin)).to.be.equals(true);
|
||||
expect(bin.toString('base64')).to.be.equals(buf.toString('base64'));
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_increment', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let a = Buffer.from('80808080', 'hex');
|
||||
let b = Buffer.from('81808080', 'hex');
|
||||
await sodium.sodium_increment(a);
|
||||
expect(await sodium.sodium_compare(b, a)).to.be.equals(0);
|
||||
|
||||
a = Buffer.from('ffffffff', 'hex');
|
||||
b = Buffer.from('00000000', 'hex');
|
||||
await sodium.sodium_increment(a);
|
||||
expect(await sodium.sodium_compare(b, a)).to.be.equals(0);
|
||||
});
|
||||
it('SodiumPlus.sodium_is_zero', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let buf;
|
||||
buf = Buffer.from('00', 'hex');
|
||||
expect(await sodium.sodium_is_zero(buf, 1)).to.be.equals(true);
|
||||
buf = Buffer.from('01', 'hex');
|
||||
expect(await sodium.sodium_is_zero(buf, 1)).to.be.equals(false);
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_memcmp', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let a, b, c;
|
||||
a = await sodium.randombytes_buf(32);
|
||||
b = await sodium.randombytes_buf(32);
|
||||
c = await Util.cloneBuffer(b);
|
||||
|
||||
expect(await sodium.sodium_memcmp(a, b)).to.be.equals(false);
|
||||
expect(await sodium.sodium_memcmp(a, c)).to.be.equals(false);
|
||||
expect(await sodium.sodium_memcmp(b, c)).to.be.equals(true);
|
||||
expect(await sodium.sodium_memcmp(c, b)).to.be.equals(true);
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_memzero', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let buf = await sodium.randombytes_buf(16);
|
||||
expect(buf.toString('hex')).to.not.equals('00000000000000000000000000000000');
|
||||
await sodium.sodium_memzero(buf);
|
||||
expect(buf.toString('hex')).to.be.equals('00000000000000000000000000000000');
|
||||
});
|
||||
|
||||
it('SodiumPlus.sodium_pad', async() => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
let buf, size, padded, unpadded;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
buf = await sodium.randombytes_buf(
|
||||
await sodium.randombytes_uniform(96) + 16
|
||||
);
|
||||
size = await sodium.randombytes_uniform(96) + 5;
|
||||
padded = await sodium.sodium_pad(buf, size);
|
||||
unpadded = await sodium.sodium_unpad(padded, size);
|
||||
expect(unpadded.toString('hex')).to.be.equals(buf.toString('hex'));
|
||||
}
|
||||
});
|
||||
});
|
30
library/sodium-plus/test/util-test.js
Normal file
30
library/sodium-plus/test/util-test.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
const { describe, it } = require('mocha');
|
||||
const { expect } = require('chai');
|
||||
const { SodiumPlus } = require('../index');
|
||||
const Util = require('../lib/util');
|
||||
const VERBOSE = false;
|
||||
const expectError = require('./async-helper');
|
||||
|
||||
let sodium;
|
||||
|
||||
(async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
if (VERBOSE) {
|
||||
console.log({
|
||||
'libsodium-wrappers': sodium.isLibsodiumWrappers(),
|
||||
'sodium-native': sodium.isSodiumNative()
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
||||
describe('Util', async () => {
|
||||
it('toBuffer()', async () => {
|
||||
if (!sodium) sodium = await SodiumPlus.auto();
|
||||
|
||||
expect(null).to.be.equal(await Util.toBuffer(null));
|
||||
|
||||
let promised = await Util.toBuffer(sodium.crypto_secretbox_keygen());
|
||||
expect(32).to.be.equal(promised.getBuffer().length);
|
||||
await expectError(Util.toBuffer(12), 'Invalid type; string or buffer expected');
|
||||
});
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" bootstrap="tests/bootstrap.php" executionOrder="depends,defects" beStrictAboutOutputDuringTests="true" failOnRisky="true" failOnWarning="true" cacheDirectory=".phpunit.cache" requireCoverageMetadata="false" beStrictAboutCoverageMetadata="true">
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" bootstrap="tests/bootstrap.php" executionOrder="depends,defects" beStrictAboutOutputDuringTests="true" failOnRisky="true" failOnWarning="true" displayDetailsOnTestsThatTriggerWarnings="true" cacheDirectory=".phpunit.cache" requireCoverageMetadata="false" beStrictAboutCoverageMetadata="true">
|
||||
<testsuites>
|
||||
<testsuite name="default">
|
||||
<directory>tests</directory>
|
||||
|
|
|
@ -23,6 +23,7 @@ class Actor extends ASObject
|
|||
public $canSearch;
|
||||
public $indexable;
|
||||
public $assertionMethod;
|
||||
public $aliases;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
|
@ -349,5 +350,24 @@ class Actor extends ASObject
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAliases()
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $aliasess
|
||||
* @return Actor
|
||||
*/
|
||||
public function setAliases($aliases)
|
||||
{
|
||||
$this->aliases = $aliases;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue