mirror of
https://github.com/cryptpad/cryptpad.git
synced 2026-09-14 11:05:41 +05:00
Merge remote-tracking branch 'origin/staging' into notification-page
# Conflicts: # customize.dist/messages.js
This commit is contained in:
commit
6ffc0878a9
5
.github/ISSUE_TEMPLATE/bug_resolution.yml
vendored
5
.github/ISSUE_TEMPLATE/bug_resolution.yml
vendored
@ -89,13 +89,10 @@ body:
|
||||
label: Version
|
||||
description: What version of CryptPad are you running?
|
||||
options:
|
||||
- 2025.3.0
|
||||
- 2024.12.0
|
||||
- 2024.9.1
|
||||
- 2024.9.0
|
||||
- 2024.6.1
|
||||
- 2024.6.0
|
||||
- 2024.3.1
|
||||
- 2024.3.0
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
117
CHANGELOG.md
117
CHANGELOG.md
@ -4,6 +4,123 @@ SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and cont
|
||||
SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
# Release (2025.3.1)
|
||||
|
||||
> [!NOTE]
|
||||
> The new version of OnlyOffice is much bigger than the previous versions. When installing version 8.3 with `install-onlyoffice.sh` ~830MB additional disk space is needed.
|
||||
|
||||
# 💐 Spring 2025 release (2025.3.0)
|
||||
|
||||
## Goals
|
||||
|
||||
This release starts the important work of refactoring CryptPad code to be more modular and optimized. The first improvements will benefit users with large drives or teams as we now avoid loading _all of your drives and shared folders_ before opening a document. We also include some admin features, numerous fixes and improvements with our usual focus on accessibility and mobile usage.
|
||||
|
||||
> [!NOTE]
|
||||
> We had planned to upgrade OnlyOffice applications (Sheet, Document, Presentation) to version 8 in this release. However we are still working on blocking bugs in the integration. Since the upgrade of documents is non-reversible we are going to keep working to fix the bugs and release `2025.3.1` with OnlyOffice 8 when ready.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This release contains security fixes, we encourage instance administrators to upgrade.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- SharedWorker build with faster loading for requested data [#1822](https://github.com/cryptpad/cryptpad/pull/1822)
|
||||
- Add and remove admins from the UI [#1801](https://github.com/cryptpad/cryptpad/pull/1801)
|
||||
- Upload diagram images on import [#1828](https://github.com/cryptpad/cryptpad/pull/1828)
|
||||
- Integration API [#1797](https://github.com/cryptpad/cryptpad/pull/1797)
|
||||
|
||||
|
||||
## Improvements
|
||||
|
||||
- Drive
|
||||
- Sort files and folders with "natural" sort [#1739](https://github.com/cryptpad/cryptpad/pull/1739) thanks to @jfly
|
||||
- "recent pads" drive category improvements [#1836](https://github.com/cryptpad/cryptpad/pull/1836)
|
||||
- Mobile
|
||||
- Enable preview mode on mobile code app [#1759](https://github.com/cryptpad/cryptpad/pull/1759)
|
||||
- Fix profile layout on small screens [#1742](https://github.com/cryptpad/cryptpad/pull/1742)
|
||||
- Buttons for moving Kanban boards and items on mobile [#1727](https://github.com/cryptpad/cryptpad/pull/1727)
|
||||
- Buttons for moving question blocks in Forms (mobile) [#1753](https://github.com/cryptpad/cryptpad/pull/1753)
|
||||
- Calendar
|
||||
- Improved calendar dropdown: keyboard accessibility and title overflow fixes [#1755](https://github.com/cryptpad/cryptpad/pull/1755)
|
||||
- OnlyOffice
|
||||
- New OnlyOffice default config options [#1820](https://github.com/cryptpad/cryptpad/pull/1820)
|
||||
- Add `--check`, `--rdfind`, `--no-rdfind` options to `install-onlyoffice.sh` [#1740](https://github.com/cryptpad/cryptpad/pull/1740) thanks to @jfly
|
||||
- OnlyOffice configurations (compact header, hide right menu, light/dark theme) [d1799d1](https://github.com/cryptpad/cryptpad/commit/d1799d106cd45b1f97251f9e0451cd519eb169d0)
|
||||
- Treat relative URLs in the sandbox as relative to the outer domain [#1752](https://github.com/cryptpad/cryptpad/pull/1752) thanks to @ansuz
|
||||
- Blob metadata refactoring [#1800](https://github.com/cryptpad/cryptpad/pull/1800)
|
||||
- Reload server subprocesses after a configured number of tasks [#1796](https://github.com/cryptpad/cryptpad/pull/1796)
|
||||
- Reduce server memory usage when accessing document history [#1795](https://github.com/cryptpad/cryptpad/pull/1795)
|
||||
- Add descriptive error messages [#1789](https://github.com/cryptpad/cryptpad/pull/1789)
|
||||
- Add Skip Link [#1774](https://github.com/cryptpad/cryptpad/pull/1774)
|
||||
|
||||
## Fixes
|
||||
|
||||
- Kanban
|
||||
- Fix kanban cursor issues when editing collaboratively [#1816](https://github.com/cryptpad/cryptpad/pull/1816)
|
||||
- Kanban "See all tags" button fix [#1812](https://github.com/cryptpad/cryptpad/pull/1812)
|
||||
- Enable keyboard usage for "Add Item" buttons in Kanban [#1802](https://github.com/cryptpad/cryptpad/pull/1802)
|
||||
- Forms
|
||||
- Conditional section after page break [#1749](https://github.com/cryptpad/cryptpad/pull/1749)
|
||||
- Fix long question text overflow and weird sizing of the required label in forms [#1747](https://github.com/cryptpad/cryptpad/pull/1747)
|
||||
- Drive
|
||||
- Fix anonymous drive download [#1784](https://github.com/cryptpad/cryptpad/pull/1784)
|
||||
- Form answers Drive download [#1711](https://github.com/cryptpad/cryptpad/pull/1711)
|
||||
- Prevent saving file to Drive multiple times [#1775](https://github.com/cryptpad/cryptpad/pull/1775)
|
||||
- Links
|
||||
- Fix link dialog focus issues & Improve error handling [#1758](https://github.com/cryptpad/cryptpad/pull/1758)
|
||||
- OnlyOffice
|
||||
- Fix /checkup/ false positive when OnlyOffice is not installed [#1731](https://github.com/cryptpad/cryptpad/pull/1731)
|
||||
- Large file uploads don't fail anymore on Chromium [#1783](https://github.com/cryptpad/cryptpad/issues/1783)
|
||||
- Fix blob Access-Control-Allow-Origin header [#1832](https://github.com/cryptpad/cryptpad/pull/1832)
|
||||
- Remove OCSP Stapling support for Nginx [#1818](https://github.com/cryptpad/cryptpad/pull/1818)
|
||||
- Notifications sidebar: Fix keyboard navigation issues [#1780](https://github.com/cryptpad/cryptpad/pull/1780)
|
||||
- Accessibility fixes to Admin UI [#1829](https://github.com/cryptpad/cryptpad/pull/1829)
|
||||
|
||||
<!---
|
||||
## Dependencies
|
||||
|
||||
nothing here?
|
||||
-->
|
||||
|
||||
## Upgrade notes
|
||||
|
||||
If you are upgrading from a version older than `2024.12.0` please read the upgrade notes of all versions between yours and `2025.3.0` to avoid configuration issues.
|
||||
|
||||
To upgrade:
|
||||
|
||||
1. Stop your server
|
||||
2. Get the latest code with git
|
||||
|
||||
```bash
|
||||
git fetch --depth 1 origin tag 2025.3.0
|
||||
git checkout 2025.3.0
|
||||
npm ci
|
||||
npm run install:components
|
||||
```
|
||||
|
||||
1. Restart your server
|
||||
2. Review your instance's checkup page to ensure that you are passing all tests
|
||||
|
||||
|
||||
### (Optional) Re-build the SharedWorker
|
||||
|
||||
|
||||
With this release we introduce `www/common/worker.bundle.min.js` which contains all code for the Shared Worker (thread common to all your CryptPad tabs) in a single built and minified file.
|
||||
|
||||
You can build this file yourself with `npm run api` before restarting the server.
|
||||
|
||||
**Note:** You must install the dev dependencies from npm if you want to build this command (don't use the `--production` flag)
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
Community: @jfly, @nisbet-hubbard
|
||||
|
||||
Alumni: @ansuz
|
||||
|
||||
CryptPad team: @AAAMON @Chouhartem @dariiing @davidbenque @DianaXWIKI @mathilde-cryptpad @wginolas @yflory @zuzanna-maria
|
||||
|
||||
|
||||
|
||||
# ❄️ Winter release (2024.12.0)
|
||||
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
@ -22,4 +22,5 @@ We do also communicate about this topic on:
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Vulnerabilities can be reported using the GitHub Security interface. You can also send us an email at security@cryptpad.org
|
||||
Brefore reaching out about a potential vulnerability, ensure it falls within the scope of our project. Please read thoroughly our [whitepaper](https://blog.cryptpad.org/2023/02/02/Whitepaper/) describing our threat model and what we consider acceptable or not security-wise. If you are sure you found a real vulnerability, you can report it using the GitHub Security interface. You can also send us an email at security@cryptpad.org
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ define([
|
||||
'chainpad-listmap',
|
||||
'/components/chainpad-crypto/crypto.js',
|
||||
'/common/common-util.js',
|
||||
'/common/outer/network-config.js',
|
||||
'/common/network-config.js',
|
||||
'/common/common-login.js',
|
||||
'/common/common-credential.js',
|
||||
'/components/chainpad/chainpad.dist.js',
|
||||
@ -53,8 +53,8 @@ define([
|
||||
var keys = Nacl.sign.keyPair();
|
||||
var inviteToken = window.location.hash.slice(1);
|
||||
localStorage.CP_sso_auth = JSON.stringify({
|
||||
s: Nacl.util.encodeBase64(keys.secretKey),
|
||||
p: Nacl.util.encodeBase64(keys.publicKey),
|
||||
s: Util.encodeBase64(keys.secretKey),
|
||||
p: Util.encodeBase64(keys.publicKey),
|
||||
token: inviteToken
|
||||
});
|
||||
ServerCommand(keys, {
|
||||
|
||||
@ -134,7 +134,13 @@ define(req, function(AppConfig, Default, Language) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// XXX
|
||||
Messages.badges_admin = "Instance administrator";
|
||||
Messages.badges_moderator = "Instance moderator";
|
||||
Messages.badges_premium = "Premium user";
|
||||
Messages.badges_error = "Error while validating this user's data";
|
||||
Messages.profile_badges = "Badges";
|
||||
|
||||
Messages.user_profile = 'Go to user profile';
|
||||
return Messages;
|
||||
|
||||
|
||||
34
customize.dist/src/less2/include/badges.less
Normal file
34
customize.dist/src/less2/include/badges.less
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
@import (reference) "./colortheme-all.less";
|
||||
@import (reference) "./variables.less";
|
||||
.badges_vars(
|
||||
@width: 30px
|
||||
) {
|
||||
@badges-width: @width;
|
||||
}
|
||||
.badges_main(@width: 30px) {
|
||||
--LessLoader_require: LessLoader_currentFile();
|
||||
.badges_vars(@width);
|
||||
--badges-width: @badges-width;
|
||||
--badges-font: ceil(@badges-width*2/3);
|
||||
}
|
||||
& {
|
||||
.badges_vars();
|
||||
i.cp-badge {
|
||||
width: var(--badges-width);
|
||||
height: var(--badges-width);
|
||||
box-sizing: border-box;
|
||||
border: 1px solid @cryptpad_text_col;
|
||||
border-radius: 50%;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: var(--badges-font);
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,6 +263,14 @@
|
||||
.cp-toolbar-userlist-friend {
|
||||
padding: 0;
|
||||
}
|
||||
.cp-userlist-badge {
|
||||
i {
|
||||
color: @cryptpad_color_brand;
|
||||
}
|
||||
i.cp-badge-error {
|
||||
color: @cryptpad_color_warn_red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,6 +104,7 @@ server {
|
||||
# Enable SharedArrayBuffer in Firefox (for .xlsx export)
|
||||
add_header Cross-Origin-Resource-Policy cross-origin;
|
||||
add_header Cross-Origin-Embedder-Policy require-corp;
|
||||
add_header Referrer-Policy same-origin;
|
||||
|
||||
# Insert the path to your CryptPad repository root here
|
||||
root /home/cryptpad/cryptpad;
|
||||
@ -169,6 +170,7 @@ server {
|
||||
# they unfortunately still require exceptions to the sandboxing to work correctly.
|
||||
if ($uri ~ ^/(?:sheet|doc|presentation)/inner.html) { set $unsafe 1; }
|
||||
if ($uri ~ ^/common/onlyoffice/.*/.*\.html) { set $unsafe 1; }
|
||||
if ($uri ~ ^/common/onlyoffice/dist/.*/sdkjs/common/spell/spell/spell.js.*$) { set $unsafe 1; }
|
||||
|
||||
# everything except the sandbox domain is a privileged scope, as they might be used to handle keys
|
||||
if ($host != $sandbox_domain) { set $unsafe 0; }
|
||||
@ -288,5 +290,5 @@ server {
|
||||
}
|
||||
|
||||
# Finally, serve anything the above exceptions don't govern.
|
||||
try_files /customize/www/$uri /customize/www/$uri/index.html /www/$uri /www/$uri/index.html /customize/$uri;
|
||||
try_files /customize/www/$uri /customize/www/$uri/index.html /www/$uri /www/$uri/index.html /src/$uri /customize/$uri;
|
||||
}
|
||||
|
||||
151
funding.json
Normal file
151
funding.json
Normal file
@ -0,0 +1,151 @@
|
||||
{
|
||||
"version": "v1.0.0",
|
||||
"drips": {
|
||||
"ethereum": {
|
||||
"ownedBy": "0xa117114b3a22e038c1545043d610dbd4029355b1"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"type": "organisation",
|
||||
"role": "owner",
|
||||
"name": "XWiki SAS",
|
||||
"email": "funding@xwiki.com",
|
||||
"phone": "",
|
||||
"description": "XWiki SAS is a European Open Source organization, maintaining Open Source Collaboration projects, XWiki and CryptPad. We believe that Open Source projects are key to getting back control on software, and that companies are important to allow the maintenance of Open Source projects.",
|
||||
"webpageUrl": {
|
||||
"url": "https://xwiki.com",
|
||||
"wellKnown": "https://xwiki.com/.well-known/funding-manifest-urls"
|
||||
}
|
||||
},
|
||||
"projects": [
|
||||
{
|
||||
"guid": "cryptpad",
|
||||
"name": "CryptPad",
|
||||
"description": "CryptPad is an end-to-end encrypted Collaboration Platform focused on providing real-time editing tools while protecting privacy.",
|
||||
"webpageUrl": {
|
||||
"url": "https://cryptpad.org",
|
||||
"wellKnown": "https://cryptpad.org/.well-known/funding-manifest-urls"
|
||||
},
|
||||
"repositoryUrl": {
|
||||
"url": "https://github.com/cryptpad/cryptpad"
|
||||
},
|
||||
"licenses": [
|
||||
"spdx:AGPL-3.0-or-later"
|
||||
],
|
||||
"tags": [
|
||||
"privacy",
|
||||
"e2ee",
|
||||
"collaboration",
|
||||
"realtimeediting",
|
||||
"office",
|
||||
"drive"
|
||||
]
|
||||
}
|
||||
],
|
||||
"funding": {
|
||||
"channels": [
|
||||
{
|
||||
"guid": "opencollective-cryptpad",
|
||||
"type": "payment-provider",
|
||||
"address": "https://opencollective.com/cryptpad",
|
||||
"description": "OpenCollective CryptPad Account"
|
||||
},
|
||||
{
|
||||
"guid": "bank",
|
||||
"type": "bank",
|
||||
"address": "Contact XWiki SAS",
|
||||
"description": "Donation by Bank Transfer or other means with XWiki SAS"
|
||||
}
|
||||
],
|
||||
"plans": [
|
||||
{
|
||||
"guid": "cryptpad-individual-helper",
|
||||
"status": "active",
|
||||
"name": "Individual Donator - Starter",
|
||||
"description": "Individual Donator would like to help us fund the maintenance and further improvement of the software.\n\n35000 people donating this every year would be needed to fund the current team to allow CryptPad to be independent from outside grants.\n\nThis plans corresponds to:\n\n- an occasional user of CryptPad\n- a regular user with limited funds\n- somebody just wanting to give us a nudge",
|
||||
"amount": 20,
|
||||
"currency": "EUR",
|
||||
"frequency": "yearly",
|
||||
"channels": [
|
||||
"opencollective-cryptpad"
|
||||
]
|
||||
},
|
||||
{
|
||||
"guid": "cryptpad-individual-user",
|
||||
"status": "active",
|
||||
"name": "Individual Donator - User",
|
||||
"description": "Individual Donator would like to help us fund the maintenance and further improvement of the software.\n\n14000 people donating this every year would be needed to fund the current team to allow CryptPad to be independent from outside grants.\n\nThis plans corresponds to:\n\n- an regular user of CryptPad\n- a privacy believer who would like to help us\n- a personal instance owner with limited funds",
|
||||
"amount": 50,
|
||||
"currency": "EUR",
|
||||
"frequency": "yearly",
|
||||
"channels": [
|
||||
"opencollective-cryptpad"
|
||||
]
|
||||
},
|
||||
{
|
||||
"guid": "cryptpad-individual-sponsor",
|
||||
"status": "active",
|
||||
"name": "Individual Donator - Sponsor",
|
||||
"description": "Individual Donator would like to help us fund the maintenance and further improvement of the software.\n\n3500 people donating this every year would be needed to fund the current team to allow CryptPad to be independent from outside grants.\n\nThis plans corresponds to:\n\n- an regular user of CryptPad who really likes CryptPad\n- a privacy believer who wants to accelerate privacy online\n- a personal or community small size instance owner",
|
||||
"amount": 200,
|
||||
"currency": "EUR",
|
||||
"frequency": "yearly",
|
||||
"channels": [
|
||||
"opencollective-cryptpad"
|
||||
]
|
||||
},
|
||||
{
|
||||
"guid": "cryptpad-instanceowner-smallorg",
|
||||
"status": "active",
|
||||
"name": "Small Organization Using CryptPad",
|
||||
"description": "Small Organization which would like to help us fund the maintenance and further improvement of the software.\n\n1500 organizations donating this every year would be needed to fund the current team to allow CryptPad to be independent from outside grants.\n\nThis plans corresponds to:\n\n- a non-profit organization having some funds hosting CryptPad for their members\n- a small company using CryptPad for its users\n- any organizations wanting Privacy software to progress",
|
||||
"amount": 500,
|
||||
"currency": "EUR",
|
||||
"frequency": "yearly",
|
||||
"channels": [
|
||||
"opencollective-cryptpad"
|
||||
]
|
||||
},
|
||||
{
|
||||
"guid": "cryptpad-instanceowner-bigorg",
|
||||
"status": "active",
|
||||
"name": "Small Organization Using CryptPad",
|
||||
"description": "Small Organization which would like to help us fund the maintenance and further improvement of the software.\n\n350 organizations donating this every year would be needed to fund the current team to allow CryptPad to be independent from outside grants.\n\nThis plans corresponds to:\n\n- a commercial company using CryptPad regularly internally or externally\n- any organization having sufficient funds wanting to support Open Source Software doing the right thing\n",
|
||||
"amount": 2000,
|
||||
"currency": "EUR",
|
||||
"frequency": "yearly",
|
||||
"channels": [
|
||||
"opencollective-cryptpad",
|
||||
"bank"
|
||||
]
|
||||
},
|
||||
{
|
||||
"guid": "cryptpad-instanceowner-bigorg",
|
||||
"status": "active",
|
||||
"name": "Organization using CryptPad heavily or as part of their offering",
|
||||
"description": "Organization using CryptPad heavily or as part of it's commercial offering and which would like to significantly contribute to it's development.\n\n70 organizations donating this every year would be needed to fund the current team to allow CryptPad to be independent from outside grants.\n\nThis plans corresponds to:\n\n- a commercial company using CryptPad heavily or as part of a commercial offering\n- foundations who would like to support the development.",
|
||||
"amount": 10000,
|
||||
"currency": "EUR",
|
||||
"frequency": "yearly",
|
||||
"channels": [
|
||||
"opencollective-cryptpad",
|
||||
"bank"
|
||||
]
|
||||
},
|
||||
{
|
||||
"guid": "cryptpad-org-funder",
|
||||
"status": "active",
|
||||
"name": "Funding organization or large company supporting the maintenance and development of CryptPad",
|
||||
"description": "This is meant for an organization investing in Privacy Preserving technologies and/or Open Source software which is important for the internet and wanting to support CryptPad with a grant. The grant can be for specific development useful for our roadmap or just for maintenance of the software.\n\n12 such grants would be needed to fund the current team.",
|
||||
"amount": 50000,
|
||||
"currency": "EUR",
|
||||
"frequency": "one-time",
|
||||
"channels": [
|
||||
"opencollective-cryptpad",
|
||||
"bank"
|
||||
]
|
||||
}
|
||||
],
|
||||
"history": []
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,10 @@ PROPS_FILE="$CONF_DIR"/onlyoffice.properties
|
||||
declare -A PROPS
|
||||
|
||||
main() {
|
||||
|
||||
# clean build env in case a previous build has failed
|
||||
rm -rf "$BUILDS_DIR"
|
||||
|
||||
mkdir -p "$CONF_DIR"
|
||||
|
||||
load_props
|
||||
@ -23,18 +27,79 @@ main() {
|
||||
|
||||
ask_for_license
|
||||
|
||||
# Remeber the 1st version that is installed. This will help us install only
|
||||
# needed OnlyOffice versions in a later version of this script.
|
||||
set_prop oldest_needed_version v1
|
||||
# Check if 'oldest_needed_version' is already set, if not, set it to v8
|
||||
if [ -z "${PROPS['oldest_needed_version']+set}" ]; then
|
||||
echo "'oldest_needed_version' is not set. Setting it to v8."
|
||||
set_prop "oldest_needed_version" "v8"
|
||||
else
|
||||
echo "'oldest_needed_version' is already set to ${PROPS['oldest_needed_version']}. No changes made."
|
||||
fi
|
||||
|
||||
mkdir -p "$OO_DIR"
|
||||
install_version v1 4f370beb
|
||||
install_version v2b d9da72fd
|
||||
install_version v4 6ebc6938
|
||||
install_version v5 88a356f0
|
||||
install_version v6 abd8a309
|
||||
install_version v7 e1267803
|
||||
install_x2t v7.3+1 ab0c05b0e4c81071acea83f0c6a8e75f5870c360ec4abc4af09105dd9b52264af9711ec0b7020e87095193ac9b6e20305e446f2321a541f743626a598e5318c1
|
||||
|
||||
available_versions=(v1 v2b v4 v5 v6 v7 v8 x2t)
|
||||
|
||||
start_installing=false
|
||||
for version in "${available_versions[@]}"; do
|
||||
if [ "$start_installing" = true ]; then
|
||||
selected_versions+=("$version")
|
||||
elif [ "$version" = "${PROPS['oldest_needed_version']}" ]; then
|
||||
start_installing=true
|
||||
selected_versions+=("$version")
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
for version in "${selected_versions[@]}"; do
|
||||
case $version in
|
||||
v1)
|
||||
set_prop oldest_needed_version v1; install_old_version v1 4f370beb
|
||||
# We delete 'help' from previous versions as they are useless and take up storage
|
||||
rm -rf "$OO_DIR/v1/web-apps/apps/documenteditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v1/web-apps/apps/presentationeditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v1/web-apps/apps/spreadsheeteditor/main/resources/help"
|
||||
;;
|
||||
v2b)
|
||||
install_old_version v2b d9da72fd
|
||||
rm -rf "$OO_DIR/v2b/web-apps/apps/documenteditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v2b/web-apps/apps/presentationeditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v2b/web-apps/apps/spreadsheeteditor/main/resources/help"
|
||||
;;
|
||||
v4)
|
||||
install_old_version v4 6ebc6938
|
||||
rm -rf "$OO_DIR/v4/web-apps/apps/documenteditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v4/web-apps/apps/presentationeditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v4/web-apps/apps/spreadsheeteditor/main/resources/help"
|
||||
;;
|
||||
v5)
|
||||
install_old_version v5 88a356f0
|
||||
rm -rf "$OO_DIR/v5/web-apps/apps/documenteditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v5/web-apps/apps/presentationeditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v5/web-apps/apps/spreadsheeteditor/main/resources/help"
|
||||
;;
|
||||
v6)
|
||||
install_old_version v6 abd8a309
|
||||
rm -rf "$OO_DIR/v6/web-apps/apps/documenteditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v6/web-apps/apps/presentationeditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v6/web-apps/apps/spreadsheeteditor/main/resources/help"
|
||||
;;
|
||||
v7)
|
||||
install_version v7 v7.3.3.60+11 1e65be6dc87d97e82b4972f303956e5397b34d637ca80a4239c48e49ab829ee5afc8f5b1680b2fb14230d63ff872ec5f9b562bb6c3f1811316b68f8b436f7ee6
|
||||
rm -rf "$OO_DIR/v7/web-apps/apps/documenteditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v7/web-apps/apps/presentationeditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v7/web-apps/apps/spreadsheeteditor/main/resources/help"
|
||||
rm -rf "$OO_DIR/v7/web-apps/apps/common/main/resources/help/"
|
||||
# From all the older versions only v7 has 'dictionaries', we remove it for the same reasons
|
||||
rm -rf "$OO_DIR/v7/dictionaries/"
|
||||
;;
|
||||
v8) install_version v8 v8.3.3.23+3 6a00704df88c87bf5810257d99e83b32b76b86326ebd668b09c257f0abc283991b9ec3c121e0801173afc4b8deb21d4539c307da26e40e42f6d4f3af195526c2 ;;
|
||||
x2t) install_x2t v7.3+1 ab0c05b0e4c81071acea83f0c6a8e75f5870c360ec4abc4af09105dd9b52264af9711ec0b7020e87095193ac9b6e20305e446f2321a541f743626a598e5318c1 ;;
|
||||
*)
|
||||
echo "Unknown version: $version"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
rm -rf "$BUILDS_DIR"
|
||||
|
||||
@ -156,23 +221,22 @@ EOF
|
||||
}
|
||||
|
||||
ensure_oo_is_downloaded() {
|
||||
ensure_command_available git
|
||||
ensure_command_available git
|
||||
|
||||
if ! [ -d "$BUILDS_DIR" ]; then
|
||||
echo "Downloading OnlyOffice..."
|
||||
git clone --bare https://github.com/cryptpad/onlyoffice-builds.git "$BUILDS_DIR"
|
||||
fi
|
||||
if [ ${TRUST_REPOSITORY+x} ] || [ "${PROPS[trust_repository]:-no}" == yes ]; then
|
||||
git config --global --add safe.directory /cryptpad/onlyoffice-conf/onlyoffice-builds.git
|
||||
fi
|
||||
if ! [ -d "$BUILDS_DIR" ]; then
|
||||
echo "Downloading OnlyOffice..."
|
||||
git clone --bare https://github.com/cryptpad/onlyoffice-builds.git "$BUILDS_DIR"
|
||||
fi
|
||||
if [ ${TRUST_REPOSITORY+x} ] || [ "${PROPS[trust_repository]:-no}" == yes ]; then
|
||||
git config --global --add safe.directory /cryptpad/onlyoffice-conf/onlyoffice-builds.git
|
||||
fi
|
||||
}
|
||||
|
||||
install_version() {
|
||||
install_old_version() {
|
||||
local DIR=$1
|
||||
local COMMIT=$2
|
||||
local FULL_DIR=$OO_DIR/$DIR
|
||||
local LAST_DIR
|
||||
LAST_DIR=$(pwd)
|
||||
local LAST_DIR=$(pwd)
|
||||
|
||||
local ACTUAL_COMMIT="not installed"
|
||||
if [ -e "$FULL_DIR"/.commit ]; then
|
||||
@ -206,6 +270,40 @@ install_version() {
|
||||
fi
|
||||
}
|
||||
|
||||
install_version() {
|
||||
ensure_command_available curl
|
||||
ensure_command_available sha512sum
|
||||
ensure_command_available unzip
|
||||
|
||||
local DIR=$1
|
||||
local VERSION=$2
|
||||
local HASH=$3
|
||||
local FULL_DIR=$OO_DIR/$DIR
|
||||
local LAST_DIR=$(pwd)
|
||||
|
||||
if [ ! -e "$FULL_DIR"/.version ] || [ "$(cat "$FULL_DIR"/.version)" != "$VERSION" ]; then
|
||||
rm -rf "$FULL_DIR"
|
||||
mkdir -p "$FULL_DIR"
|
||||
|
||||
cd "$FULL_DIR"
|
||||
|
||||
curl "https://github.com/cryptpad/onlyoffice-editor/releases/download/$VERSION/onlyoffice-editor.zip" --location --output "onlyoffice-editor.zip"
|
||||
echo "$HASH onlyoffice-editor.zip" >onlyoffice-editor.zip.sha512
|
||||
if ! sha512sum --check onlyoffice-editor.zip.sha512; then
|
||||
echo "onlyoffice-editor.zip does not match expected checksum"
|
||||
exit 1
|
||||
fi
|
||||
unzip onlyoffice-editor.zip
|
||||
rm onlyoffice-editor.zip*
|
||||
|
||||
echo "$VERSION" >"$FULL_DIR"/.version
|
||||
|
||||
echo "$DIR updated"
|
||||
else
|
||||
echo "$DIR was up to date"
|
||||
fi
|
||||
}
|
||||
|
||||
install_x2t() {
|
||||
local VERSION=$1
|
||||
local HASH=$2
|
||||
@ -233,7 +331,6 @@ install_x2t() {
|
||||
ensure_command_available sha512sum
|
||||
ensure_command_available unzip
|
||||
curl "https://github.com/cryptpad/onlyoffice-x2t-wasm/releases/download/$VERSION/x2t.zip" --location --output x2t.zip
|
||||
# curl "https://github.com/cryptpad/onlyoffice-x2t-wasm/releases/download/v7.3%2B1/x2t.zip" --location --output x2t.zip
|
||||
echo "$HASH x2t.zip" >x2t.zip.sha512
|
||||
if ! sha512sum --check x2t.zip.sha512; then
|
||||
echo "x2t.zip does not match expected checksum"
|
||||
|
||||
@ -12,6 +12,7 @@ const Fse = require("fs-extra");
|
||||
const Path = require("path");
|
||||
const Nacl = require("tweetnacl/nacl-fast");
|
||||
const Hash = require('./common-hash');
|
||||
const Util = require('./common-util');
|
||||
|
||||
module.exports.create = function (Env) {
|
||||
var log = Env.Log;
|
||||
@ -92,7 +93,7 @@ nThen(function (w) {
|
||||
if (typeof(Env.bearerSecret) === 'string') { return; }
|
||||
// if one does not exist, then create one and remember it
|
||||
// 256 bits
|
||||
var bearerSecret = Nacl.util.encodeBase64(Nacl.randomBytes(32));
|
||||
var bearerSecret = Util.encodeBase64(Nacl.randomBytes(32));
|
||||
Env.Log.info("GENERATING_BEARER_SECRET", {});
|
||||
Decrees.write(Env, [
|
||||
'SET_BEARER_SECRET',
|
||||
|
||||
@ -44,14 +44,14 @@ Block.validateLoginBlock = function (Env, publicKey, signature, block, _cb) {
|
||||
|
||||
var u8_public_key;
|
||||
try {
|
||||
u8_public_key = Nacl.util.decodeBase64(publicKey);
|
||||
u8_public_key = Util.decodeBase64(publicKey);
|
||||
} catch (e) {
|
||||
return void cb('E_INVALID_KEY');
|
||||
}
|
||||
|
||||
var u8_signature;
|
||||
try {
|
||||
u8_signature = Nacl.util.decodeBase64(signature);
|
||||
u8_signature = Util.decodeBase64(signature);
|
||||
} catch (e) {
|
||||
Env.Log.error('INVALID_BLOCK_SIGNATURE', e);
|
||||
return void cb('E_INVALID_SIGNATURE');
|
||||
@ -60,7 +60,7 @@ Block.validateLoginBlock = function (Env, publicKey, signature, block, _cb) {
|
||||
// convert the block to a Uint8Array
|
||||
var u8_block;
|
||||
try {
|
||||
u8_block = Nacl.util.decodeBase64(block);
|
||||
u8_block = Util.decodeBase64(block);
|
||||
} catch (e) {
|
||||
return void cb('E_INVALID_BLOCK');
|
||||
}
|
||||
@ -85,9 +85,9 @@ Block.validateAncestorProof = function (Env, proof, _cb) {
|
||||
try {
|
||||
var parsed = JSON.parse(proof);
|
||||
var pub = parsed[0];
|
||||
var u8_pub = Nacl.util.decodeBase64(pub);
|
||||
var u8_pub = Util.decodeBase64(pub);
|
||||
var sig = parsed[1];
|
||||
var u8_sig = Nacl.util.decodeBase64(sig);
|
||||
var u8_sig = Util.decodeBase64(sig);
|
||||
var valid = false;
|
||||
nThen(function (w) {
|
||||
valid = Nacl.sign.detached.verify(u8_pub, u8_sig, u8_pub);
|
||||
@ -159,7 +159,7 @@ Block.writeLoginBlock = function (Env, msg, _cb) {
|
||||
}).nThen(function () {
|
||||
var buffer;
|
||||
try {
|
||||
buffer = Buffer.from(Nacl.util.decodeBase64(validatedBlock));
|
||||
buffer = Buffer.from(Util.decodeBase64(validatedBlock));
|
||||
} catch (err) {
|
||||
return void cb('E_BLOCK_DESERIALIZATION');
|
||||
}
|
||||
|
||||
@ -225,8 +225,8 @@ Channel.deleteMailboxMessage = function (Env, data, cb) {
|
||||
const proof = data.proof;
|
||||
let nonce, proofBytes;
|
||||
try {
|
||||
nonce = Nacl.util.decodeBase64(proof.split('|')[0]);
|
||||
proofBytes = Nacl.util.decodeBase64(proof.split('|')[1]);
|
||||
nonce = Util.decodeBase64(proof.split('|')[0]);
|
||||
proofBytes = Util.decodeBase64(proof.split('|')[1]);
|
||||
} catch (e) {
|
||||
return void cb('EINVAL');
|
||||
}
|
||||
@ -234,10 +234,10 @@ Channel.deleteMailboxMessage = function (Env, data, cb) {
|
||||
// Check if you're allowed to delete this hash
|
||||
try {
|
||||
const mySecret = Env.curvePrivate;
|
||||
const msgBytes = Nacl.util.decodeBase64(msg).subarray(64); // Remove signature
|
||||
const msgBytes = Util.decodeBase64(msg).subarray(64); // Remove signature
|
||||
const theirPublic = msgBytes.subarray(24,56); // 0-24 = nonce; 24-56=publickey (32 bytes)
|
||||
const hashBytes = Nacl.box.open(proofBytes, nonce, theirPublic, mySecret);
|
||||
return Nacl.util.encodeUTF8(hashBytes) === hash;
|
||||
return Util.encodeUTF8(hashBytes) === hash;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -309,3 +309,9 @@ Pinning.getDeletedPads = function (Env, channels, cb) {
|
||||
Pinning.isChannelPinned = function (Env, channel, cb) {
|
||||
return void cb(void 0, true);
|
||||
};
|
||||
|
||||
Pinning.isPremium = function (Env, userKey, cb) {
|
||||
const limit = Env.limits[userKey];
|
||||
return void cb(void 0, !!limit?.plan);
|
||||
//return void cb(void 0, (limit?.plan && limit.plan !== "custom"));
|
||||
};
|
||||
|
||||
@ -2,5 +2,5 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
module.exports = require("../www/common/common-hash");
|
||||
module.exports = require("../src/common/common-hash");
|
||||
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
module.exports = require("../www/common/common-util");
|
||||
module.exports = require("../src/common/common-util");
|
||||
|
||||
@ -57,6 +57,7 @@ Default.httpHeaders = function (Env) {
|
||||
"X-XSS-Protection": "1; mode=block",
|
||||
"X-Content-Type-Options": "nosniff",
|
||||
"Access-Control-Allow-Origin": Env.enableEmbedding? '*': Env.permittedEmbedders,
|
||||
"Referrer-Policy": "same-origin",
|
||||
"Permissions-policy":"interest-cohort=()"
|
||||
};
|
||||
};
|
||||
|
||||
@ -254,7 +254,7 @@ module.exports.create = function (config) {
|
||||
// initialized as undefined
|
||||
bearerSecret: void 0,
|
||||
curvePrivate: curve.secretKey,
|
||||
curvePublic: Nacl.util.encodeBase64(curve.publicKey),
|
||||
curvePublic: Util.encodeBase64(curve.publicKey),
|
||||
|
||||
selfDestructTo: {},
|
||||
};
|
||||
|
||||
127
lib/eviction.js
127
lib/eviction.js
@ -8,9 +8,7 @@ var Util = require("../lib/common-util");
|
||||
var Pins = require("../lib/pins");
|
||||
var Keys = require("./keys");
|
||||
var Path = require('node:path');
|
||||
var config = require("./load-config");
|
||||
var Fs = require("node:fs");
|
||||
var Fse = require("fs-extra");
|
||||
|
||||
var getNewestTime = function (stats) {
|
||||
return stats[['atime', 'ctime', 'mtime'].reduce(function (a, b) {
|
||||
@ -76,103 +74,6 @@ var evictArchived = function (Env, cb) {
|
||||
blobs = Env.blobStore;
|
||||
};
|
||||
|
||||
var migrateBlobRoot = function (from, to) {
|
||||
// only migrate subpaths, leave everything else alone
|
||||
if (!Path.dirname(from).startsWith(Path.dirname(to))) { return; }
|
||||
|
||||
// expects a directory
|
||||
var recurse = function (relativePath) {
|
||||
var src = Path.join(from, relativePath);
|
||||
var children;
|
||||
try {
|
||||
children = Fs.readdirSync(src);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') { return; }
|
||||
// if you can't read a directory's contents
|
||||
// then nothing else will work, so just abort
|
||||
Log.verbose("EVICT_ARCHIVED_NOT_DIRECTORY", {
|
||||
error: err,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var dest;
|
||||
if (children.length === 0) {
|
||||
try {
|
||||
Fse.removeSync(src);
|
||||
} catch (err2) {
|
||||
Log.error('EVICT_ARCHIVED_EMPTY_DIR_REMOVAL', {
|
||||
error: err2,
|
||||
});
|
||||
// removal is non-essential, so we can continue
|
||||
}
|
||||
} else {
|
||||
// make an equivalent path in the target directory
|
||||
dest = Path.join(to, relativePath);
|
||||
|
||||
try {
|
||||
Fse.mkdirpSync(dest);
|
||||
} catch (err3) {
|
||||
Log.error("EVICT_ARCHIVED_BLOB_MIGRATION", {
|
||||
error: err3,
|
||||
});
|
||||
|
||||
// failure to create the host directory
|
||||
// will cause problems when we try to move
|
||||
// so bail out here
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
children.forEach(function (child) {
|
||||
var childSrcPath = Path.join(src, child);
|
||||
var stat = Fs.statSync(childSrcPath);
|
||||
if (stat.isDirectory()) {
|
||||
return void recurse(Path.join(relativePath, child));
|
||||
}
|
||||
|
||||
var childDestPath = Path.join(dest, child);
|
||||
|
||||
try {
|
||||
Log.verbose("EVICT_ARCHIVED_MOVE_FROM_DEPRECATED_PATH", {
|
||||
from: childSrcPath,
|
||||
to: childDestPath,
|
||||
});
|
||||
Fse.moveSync(childSrcPath, childDestPath, {
|
||||
overwrite: false,
|
||||
});
|
||||
} catch (err4) {
|
||||
Log.error('EVICT_ARCHIVED_MOVE_FAILURE', {
|
||||
error: err4,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
recurse('');
|
||||
};
|
||||
|
||||
/* In CryptPad 5.2.0 we merged a patch which converted
|
||||
all of CryptPad's root filepaths to their absolute form,
|
||||
rather than the relative paths we'd been using until then.
|
||||
Unfortunately, we overlooked a case where two absolute
|
||||
paths were concatenated together, resulting in blobs being
|
||||
archived to an incorrect path.
|
||||
|
||||
This migration detects evidence of incorrect archivals
|
||||
and moves such archived files to their intended location
|
||||
before continuing with the normal eviction procedure.
|
||||
*/
|
||||
var migrateIncorrectBlobs = function () {
|
||||
var incorrectPaths = [
|
||||
Path.join(Env.paths.archive, config.blobPath),
|
||||
Path.join(Env.paths.archive, Path.resolve(config.blobPath))
|
||||
];
|
||||
var correctPath = Path.join(Env.paths.archive, 'blob');
|
||||
incorrectPaths.forEach(root => {
|
||||
migrateBlobRoot(root, correctPath);
|
||||
});
|
||||
};
|
||||
|
||||
var removeArchivedChannels = function (w) {
|
||||
// this block will iterate over archived channels and removes them
|
||||
// if they've been in cold storage for longer than your configured archive time
|
||||
@ -236,6 +137,30 @@ var evictArchived = function (Env, cb) {
|
||||
store.listArchivedChannels(handler, w(done));
|
||||
};
|
||||
|
||||
// Blob proofs are no longer supported and can't be restored
|
||||
// so we can delete them all
|
||||
var removeArchivedBlobProofs = function (w) {
|
||||
var archivePath = Path.join(Env.paths.archive, 'blob');
|
||||
const cb = Util.once(w());
|
||||
let i = 0;
|
||||
nThen(w => {
|
||||
Fs.readdir(archivePath, w((err, list) => {
|
||||
if (err) { return; }
|
||||
list.forEach(dir => {
|
||||
// Look for 3 characters long folders
|
||||
if (dir.length !== 3) { return; }
|
||||
let path = Path.join(archivePath, dir);
|
||||
Fs.rm(path, { recursive: true, force: true }, w(err => {
|
||||
if (err) { return; }
|
||||
i++;
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}).nThen(() => {
|
||||
Log.info('EVICT_ARCHIVED_BLOB_PROOFS', i);
|
||||
cb();
|
||||
});
|
||||
};
|
||||
var removeArchivedBlobs = function (w) {
|
||||
if (typeof(Env.archiveRetentionTime) !== "number") { return; }
|
||||
// Iterate over archived blobs and remove them
|
||||
@ -269,8 +194,8 @@ var evictArchived = function (Env, cb) {
|
||||
|
||||
if (Env.DRY_RUN) { Env.Log.info('DRY RUN'); }
|
||||
nThen(loadStorage)
|
||||
.nThen(migrateIncorrectBlobs)
|
||||
.nThen(removeArchivedChannels)
|
||||
.nThen(removeArchivedBlobProofs)
|
||||
.nThen(removeArchivedBlobs)
|
||||
.nThen(function () {
|
||||
cb(void 0, report);
|
||||
@ -588,7 +513,7 @@ module.exports = function (Env, cb) {
|
||||
if (newerItem && getNewestTime(newerItem) > retentionTime) {
|
||||
// it's actually active, so don't archive it.
|
||||
w.abort();
|
||||
cb();
|
||||
next();
|
||||
}
|
||||
// else fall through to the archival
|
||||
}));
|
||||
|
||||
@ -116,7 +116,7 @@ HK.closeNetfluxSession = function (Env, netfluxId) {
|
||||
const isValidValidateKeyString = function (key) {
|
||||
try {
|
||||
return typeof(key) === 'string' &&
|
||||
Nacl.util.decodeBase64(key).length === Nacl.sign.publicKeyLength;
|
||||
Util.decodeBase64(key).length === Nacl.sign.publicKeyLength;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ COMMANDS.SSO_UPDATE_BLOCK = SSO.SSO_UPDATE_BLOCK; // Password change
|
||||
COMMANDS.SSO_VALIDATE = SSO.SSO_VALIDATE;
|
||||
*/
|
||||
|
||||
var randomToken = () => Nacl.util.encodeBase64(Nacl.randomBytes(24)).replace(/\//g, '-');
|
||||
var randomToken = () => Util.encodeBase64(Nacl.randomBytes(24)).replace(/\//g, '-');
|
||||
|
||||
// this function handles the first stage of the protocol
|
||||
// (the server's validation of the client's request and the generation of its challenge)
|
||||
@ -278,9 +278,9 @@ var handleResponse = function (Env, req, res) {
|
||||
u8_publicKey;
|
||||
|
||||
try {
|
||||
u8_toVerify = Nacl.util.decodeUTF8(text);
|
||||
u8_sig = Nacl.util.decodeBase64(sig);
|
||||
u8_publicKey = Nacl.util.decodeBase64(publicKey);
|
||||
u8_toVerify = Util.decodeUTF8(text);
|
||||
u8_sig = Util.decodeBase64(sig);
|
||||
u8_publicKey = Util.decodeBase64(publicKey);
|
||||
} catch (err3) {
|
||||
Env.Log.error('CHALLENGE_RESPONSE_DECODING_ERROR', {
|
||||
text: text,
|
||||
|
||||
@ -18,6 +18,7 @@ const bodyParser = require('body-parser');
|
||||
const BlobStore = require("./storage/blob");
|
||||
const BlockStore = require("./storage/block");
|
||||
const plugins = require("./plugin-manager");
|
||||
const gzipStatic = require('connect-gzip-static');
|
||||
|
||||
const DEFAULT_QUERY_TIMEOUT = 5000;
|
||||
const PID = process.pid;
|
||||
@ -134,6 +135,7 @@ var applyHeaderMap = function (res, map) {
|
||||
|
||||
var EXEMPT = [
|
||||
/^\/common\/onlyoffice\/.*\.html.*/,
|
||||
/^\/common\/onlyoffice\/dist\/.*\/sdkjs\/common\/spell\/spell\/spell.js.*/, // OnlyOffice loads spell.wasm in a way that needs unsave-eval
|
||||
/^\/(sheet|presentation|doc)\/inner\.html.*/,
|
||||
/^\/unsafeiframe\/inner\.html.*$/,
|
||||
];
|
||||
@ -326,11 +328,19 @@ app.use(function (req, res, next) {
|
||||
next();
|
||||
});
|
||||
|
||||
Object.keys(plugins || {}).forEach(name => {
|
||||
let plugin = plugins[name];
|
||||
if (!plugin.addHttpEndpoints) { return; }
|
||||
plugin.addHttpEndpoints(Env, app);
|
||||
});
|
||||
|
||||
|
||||
// serve custom app content from the customize directory
|
||||
// useful for testing pages customized with opengraph data
|
||||
app.use(Express.static(Path.resolve('./customize/www')));
|
||||
app.use(Express.static(Path.resolve('./www')));
|
||||
app.use(gzipStatic(Path.resolve('./www')));
|
||||
|
||||
app.use("/common", Express.static('./src/common'));
|
||||
|
||||
var mainPages = Env.mainPages || Default.mainPages();
|
||||
var mainPagePattern = new RegExp('^\/(' + mainPages.join('|') + ').html$');
|
||||
@ -359,6 +369,9 @@ app.use('/block/', function (req, res, next) {
|
||||
// block access control only applies to files
|
||||
// identified by base64-encoded public keys
|
||||
// skip everything else, ie. /block/placeholder.txt
|
||||
if (/placeholder\.txt(\?.+)?/.test(parsed.base)) {
|
||||
return void next();
|
||||
}
|
||||
if (typeof(name) !== 'string' || name.length !== 44) {
|
||||
return void res.status(404).json({
|
||||
error: "INVALID_ID",
|
||||
@ -533,12 +546,6 @@ app.use("/block", (req, res, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
Object.keys(plugins || {}).forEach(name => {
|
||||
let plugin = plugins[name];
|
||||
if (!plugin.addHttpEndpoints) { return; }
|
||||
plugin.addHttpEndpoints(Env, app);
|
||||
});
|
||||
|
||||
app.use("/customize", Express.static('customize'));
|
||||
app.use("/customize", Express.static('customize.dist'));
|
||||
app.use("/customize.dist", Express.static('customize.dist'));
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
module.exports = require("../www/common/common-signing-keys");
|
||||
module.exports = require("../src/common/common-signing-keys");
|
||||
|
||||
30
lib/pins.js
30
lib/pins.js
@ -8,6 +8,7 @@ const Fs = require("fs");
|
||||
const Path = require("path");
|
||||
const Util = require("./common-util");
|
||||
const Plan = require("./plan");
|
||||
const Store = require('./storage/file');
|
||||
|
||||
const Semaphore = require('saferphore');
|
||||
const nThen = require('nthen');
|
||||
@ -258,8 +259,20 @@ Pins.load = function (cb, config) {
|
||||
var pinPath = config.pinPath || './pins';
|
||||
var done = Util.once(cb);
|
||||
var handler = config.handler;
|
||||
let store;
|
||||
|
||||
nThen((waitFor) => {
|
||||
Store.create({
|
||||
filePath: config.pinPath,
|
||||
volumeId: 'pins'
|
||||
}, waitFor((err, _) => {
|
||||
if (err) {
|
||||
waitFor.abort();
|
||||
return void done(err);
|
||||
}
|
||||
store = _;
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
// recurse over the configured pinPath, or the default
|
||||
Fs.readdir(pinPath, waitFor((err, list) => {
|
||||
if (err) {
|
||||
@ -283,26 +296,29 @@ Pins.load = function (cb, config) {
|
||||
}
|
||||
list2.forEach((ff) => {
|
||||
if (config && config.exclude && config.exclude.indexOf(ff) > -1) { return; }
|
||||
fileList.push(Path.join(pinPath, f, ff));
|
||||
fileList.push(ff.replace(/(\.ndjson)$/, ''));
|
||||
});
|
||||
})));
|
||||
});
|
||||
});
|
||||
}).nThen((waitFor) => {
|
||||
fileList.forEach((f) => {
|
||||
fileList.forEach((id) => {
|
||||
sema.take((returnAfter) => {
|
||||
var next = waitFor(returnAfter());
|
||||
Fs.readFile(f, (err, content) => {
|
||||
var ref = {};
|
||||
var h = createLineHandler(ref, id);
|
||||
store.readMessagesBin(id, 0, (msgObj, next) => {
|
||||
h(msgObj.buff.toString('utf8'));
|
||||
next();
|
||||
}, (err) => {
|
||||
if (err) {
|
||||
waitFor.abort();
|
||||
return void done(err);
|
||||
}
|
||||
var id = f.replace(/.*\/([^/]*).ndjson$/, (x, y)=>y);
|
||||
var contentString = content.toString('utf8');
|
||||
if (handler) {
|
||||
return void handler(processPinFile(contentString, f), id, next);
|
||||
return void handler(ref, id, next);
|
||||
}
|
||||
const hashes = Pins.calculateFromLog(contentString, f);
|
||||
const hashes = Object.keys(ref.pins);
|
||||
hashes.forEach((x) => {
|
||||
(pinned[x] = pinned[x] || {})[id] = 1;
|
||||
});
|
||||
|
||||
@ -24,6 +24,7 @@ const UNAUTHENTICATED_CALLS = {
|
||||
WRITE_PRIVATE_MESSAGE: Channel.writePrivateMessage,
|
||||
DELETE_MAILBOX_MESSAGE: Channel.deleteMailboxMessage,
|
||||
GET_METADATA: Metadata.getMetadata,
|
||||
IS_PREMIUM: Pinning.isPremium,
|
||||
ADD_FIRST_ADMIN: Admin.addFirstAdmin
|
||||
};
|
||||
|
||||
|
||||
@ -473,9 +473,29 @@ var archiveBlob = function (Env, blobId, reason, cb) {
|
||||
};
|
||||
|
||||
var removeArchivedBlob = function (Env, blobId, cb) {
|
||||
var CB = Util.once(cb);
|
||||
var archivePath = prependArchive(Env, makeBlobPath(Env, blobId));
|
||||
var metadataPath = prependArchive(Env, mkMetadataPath(Env, blobId));
|
||||
Fs.unlink(archivePath, cb);
|
||||
removeArchivedActivity(Env, blobId, () => {});
|
||||
nThen(function (w) {
|
||||
Fs.unlink(archivePath, w(function (err) {
|
||||
if (err) {
|
||||
if (err.code === "ENOENT") { return; }
|
||||
w.abort();
|
||||
CB("E_ARCHIVED_BLOB_REMOVAL_"+ err.code);
|
||||
}
|
||||
}));
|
||||
Fs.unlink(metadataPath, w(function (err) {
|
||||
if (err) {
|
||||
if (err.code === "ENOENT") { return; }
|
||||
w.abort();
|
||||
CB("E_ARCHIVED_BLOBMD_REMOVAL_"+ err.code);
|
||||
}
|
||||
}));
|
||||
removeArchivedActivity(Env, blobId, () => {});
|
||||
}).nThen(function () {
|
||||
CB();
|
||||
});
|
||||
};
|
||||
|
||||
// restoreBlob
|
||||
|
||||
@ -573,6 +573,7 @@ var removeArchivedChannel = function (env, channelName, cb) {
|
||||
nThen(function (w) {
|
||||
Fs.unlink(channelPath, w(function (err) {
|
||||
if (err) {
|
||||
if (err.code === "ENOENT") { return; }
|
||||
w.abort();
|
||||
CB(labelError("E_ARCHIVED_CHANNEL_REMOVAL", err));
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ var pathFromId = function (Env, id, ref) {
|
||||
return Path.join(Env.paths.base, "sessions", id.slice(0, 2), id, ref);
|
||||
};
|
||||
|
||||
Sessions.randomId = () => Nacl.util.encodeBase64(Nacl.randomBytes(24)).replace(/\//g, '-');
|
||||
Sessions.randomId = () => Util.encodeBase64(Nacl.randomBytes(24)).replace(/\//g, '-');
|
||||
|
||||
Sessions.read = function (Env, id, ref, cb) {
|
||||
var path = pathFromId(Env, id, ref);
|
||||
|
||||
@ -7,6 +7,7 @@ var Fse = require("fs-extra");
|
||||
var Path = require("path");
|
||||
var nacl = require("tweetnacl/nacl-fast");
|
||||
var nThen = require("nthen");
|
||||
var Util = require('../common-util');
|
||||
|
||||
var Tasks = module.exports;
|
||||
|
||||
@ -49,7 +50,7 @@ var makeDirectoryId = function (d) {
|
||||
|
||||
var write = function (env, task, cb) {
|
||||
var str = JSON.stringify(task) + '\n';
|
||||
var id = nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(str))).replace(/\//g, '-');
|
||||
var id = Util.encodeBase64(nacl.hash(Util.decodeUTF8(str))).replace(/\//g, '-');
|
||||
|
||||
var dir = makeDirectoryId(task[0]);
|
||||
var path = Path.join(env.root, dir);
|
||||
|
||||
@ -772,14 +772,14 @@ COMMANDS.INLINE = function (data, cb) {
|
||||
monitoringIncrement('inlineValidation');
|
||||
var signedMsg;
|
||||
try {
|
||||
signedMsg = Nacl.util.decodeBase64(data.msg);
|
||||
signedMsg = Util.decodeBase64(data.msg);
|
||||
} catch (e) {
|
||||
return void cb('E_BAD_MESSAGE');
|
||||
}
|
||||
|
||||
var validateKey;
|
||||
try {
|
||||
validateKey = Nacl.util.decodeBase64(data.key);
|
||||
validateKey = Util.decodeBase64(data.key);
|
||||
} catch (e) {
|
||||
return void cb("E_BADKEY");
|
||||
}
|
||||
@ -801,19 +801,19 @@ const checkDetachedSignature = function (signedMsg, signature, publicKey) {
|
||||
var signatureBuffer;
|
||||
|
||||
try {
|
||||
signedBuffer = Nacl.util.decodeUTF8(signedMsg);
|
||||
signedBuffer = Util.decodeUTF8(signedMsg);
|
||||
} catch (e) {
|
||||
throw new Error("INVALID_SIGNED_BUFFER");
|
||||
}
|
||||
|
||||
try {
|
||||
pubBuffer = Nacl.util.decodeBase64(publicKey);
|
||||
pubBuffer = Util.decodeBase64(publicKey);
|
||||
} catch (e) {
|
||||
throw new Error("INVALID_PUBLIC_KEY");
|
||||
}
|
||||
|
||||
try {
|
||||
signatureBuffer = Nacl.util.decodeBase64(signature);
|
||||
signatureBuffer = Util.decodeBase64(signature);
|
||||
} catch (e) {
|
||||
throw new Error("INVALID_SIGNATURE");
|
||||
}
|
||||
@ -851,8 +851,7 @@ COMMANDS.HASH_CHANNEL_LIST = function (data, cb) {
|
||||
});
|
||||
uniques.sort();
|
||||
|
||||
var hash = Nacl.util.encodeBase64(Nacl.hash(Nacl
|
||||
.util.decodeUTF8(JSON.stringify(uniques))));
|
||||
var hash = Util.encodeBase64(Nacl.hash(Util.decodeUTF8(JSON.stringify(uniques))));
|
||||
|
||||
cb(void 0, hash);
|
||||
};
|
||||
|
||||
@ -53,7 +53,7 @@ Workers.initialize = function (Env, config, _cb) {
|
||||
//return Object.keys(workers[index].tasks || {}).length;
|
||||
};
|
||||
|
||||
const WORKER_TASK_LIMIT = 100000; // XXX
|
||||
const WORKER_TASK_LIMIT = 250000; // XXX
|
||||
|
||||
var workerOffset = -1;
|
||||
var queue = [];
|
||||
@ -260,6 +260,16 @@ Workers.initialize = function (Env, config, _cb) {
|
||||
pid: worker.pid, // store the child process's id in an easily accessible location
|
||||
};
|
||||
|
||||
let pid = worker.pid;
|
||||
const onWorkerClosed = () => {
|
||||
Object.keys(Env.plugins || {}).forEach(name => {
|
||||
let plugin = Env.plugins[name];
|
||||
if (!plugin.onWorkerClosed) { return; }
|
||||
try { plugin.onWorkerClosed("db-worker", pid); }
|
||||
catch (e) {}
|
||||
});
|
||||
};
|
||||
|
||||
state.replaceWorker = () => {
|
||||
let index = workers.indexOf(state);
|
||||
if (index === -1) { return; }
|
||||
@ -291,6 +301,7 @@ Workers.initialize = function (Env, config, _cb) {
|
||||
worker: state.worker.pid,
|
||||
count: state.count
|
||||
});
|
||||
onWorkerClosed();
|
||||
delete state.worker;
|
||||
worker.kill();
|
||||
};
|
||||
@ -323,14 +334,8 @@ Workers.initialize = function (Env, config, _cb) {
|
||||
handleResponse(state, res);
|
||||
});
|
||||
|
||||
let pid = worker.pid;
|
||||
var substituteWorker = Util.once(function () {
|
||||
Object.keys(Env.plugins || {}).forEach(name => {
|
||||
let plugin = Env.plugins[name];
|
||||
if (!plugin.onWorkerClosed) { return; }
|
||||
try { plugin.onWorkerClosed("db-worker", pid); }
|
||||
catch (e) {}
|
||||
});
|
||||
onWorkerClosed();
|
||||
|
||||
Env.Log.info("SUBSTITUTE_DB_WORKER", '');
|
||||
var idx = workers.indexOf(state);
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2025 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
// Move file from "src" to "www"
|
||||
// This script can be used to copy src files into their old location in order to
|
||||
// merge code more easily.
|
||||
// Set REVERSE to true to copy from "www" to "src" once the changes have been merged.
|
||||
|
||||
const REVERSE = true;
|
||||
const Fs = require('node:fs');
|
||||
const map = {
|
||||
'./src/worker/components/roster.js': './www/common/outer/roster.js',
|
||||
'./src/worker/components/sharedfolder.js': './www/common/outer/sharedfolder.js',
|
||||
|
||||
|
||||
|
||||
'./src/common/cache-store.js': './www/common/outer/cache-store.js',
|
||||
'./src/common/common-constants.js': './www/common/common-constants.js',
|
||||
'./src/common/common-credential.js': './www/common/common-credential.js',
|
||||
'./src/common/common-feedback.js': './www/common/common-feedback.js',
|
||||
'./src/common/common-hash.js': './www/common/common-hash.js',
|
||||
'./src/common/common-messaging.js': './www/common/common-messaging.js',
|
||||
'./src/common/common-realtime.js': './www/common/common-realtime.js',
|
||||
'./src/common/common-signing-keys.js': './www/common/common-signing-keys.js',
|
||||
'./src/common/common-util.js': './www/common/common-util.js',
|
||||
'./src/common/cryptget.js': './www/common/cryptget.js',
|
||||
'./src/common/http-command.js': './www/common/outer/http-command.js',
|
||||
'./src/common/login-block.js': './www/common/outer/login-block.js',
|
||||
'./src/common/network-config.js': './www/common/outer/network-config.js',
|
||||
'./src/common/notify.js': './www/common/notify.js',
|
||||
'./src/common/onlyoffice/current-version.js': './www/common/onlyoffice/current-version.js',
|
||||
'./src/common/pad-types.js': './www/common/pad-types.js',
|
||||
'./src/common/pinpad.js': './www/common/pinpad.js',
|
||||
'./src/common/proxy-manager.js': './www/common/proxy-manager.js',
|
||||
'./src/common/recurrence.js': './www/calendar/recurrence.js',
|
||||
'./src/common/rpc.js': './www/common/rpc.js',
|
||||
'./src/common/user-object.js': './www/common/user-object.js',
|
||||
'./src/common/user-object-setter.js': './www/common/user-object-setter.js',
|
||||
'./src/common/worker-channel.js': './www/common/outer/worker-channel.js'
|
||||
};
|
||||
|
||||
Object.keys(map).forEach(newPath => {
|
||||
let oldPath = map[newPath];
|
||||
if (!Fs.existsSync(newPath)) {
|
||||
throw new Error("File path mismatch: " + newPath);
|
||||
}
|
||||
if (!Fs.existsSync(oldPath)) {
|
||||
throw new Error("File path mismatch: " + oldPath);
|
||||
}
|
||||
const from = REVERSE ? oldPath : newPath;
|
||||
const to = REVERSE ? newPath : oldPath;
|
||||
Fs.cpSync(from, to);
|
||||
});
|
||||
89
package-lock.json
generated
89
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "cryptpad",
|
||||
"version": "2025.3.0",
|
||||
"version": "2025.3.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "cryptpad",
|
||||
"version": "2025.3.0",
|
||||
"version": "2025.3.1",
|
||||
"license": "AGPL-3.0+",
|
||||
"dependencies": {
|
||||
"@mcrowe/minibloom": "^0.2.0",
|
||||
@ -16,13 +16,14 @@
|
||||
"bootstrap": "^4.0.0",
|
||||
"bootstrap-tokenfield": "^0.12.0",
|
||||
"chainpad": "^5.2.6",
|
||||
"chainpad-crypto": "^0.2.5",
|
||||
"chainpad-listmap": "^1.1.1",
|
||||
"chainpad-netflux": "^1.2.2",
|
||||
"chainpad-crypto": "^0.3.0",
|
||||
"chainpad-listmap": "^1.2.0",
|
||||
"chainpad-netflux": "^1.3.0",
|
||||
"chainpad-server": "^5.2.4",
|
||||
"ckeditor": "npm:ckeditor4@~4.22.1",
|
||||
"codemirror": "^5.19.0",
|
||||
"components-font-awesome": "^4.6.3",
|
||||
"connect-gzip-static": "^4.2.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"croppie": "^2.5.0",
|
||||
"dragula": "3.7.2",
|
||||
@ -58,7 +59,8 @@
|
||||
"sortify": "^1.0.4",
|
||||
"stream-to-pull-stream": "^1.7.2",
|
||||
"thirty-two": "^1.0.2",
|
||||
"tweetnacl": "file:./src/tweetnacl",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"tweetnacl-util": "^0.15.1",
|
||||
"ulimit": "0.0.2",
|
||||
"ws": "^8.17.1",
|
||||
"x2js": "^3.4.4"
|
||||
@ -1902,19 +1904,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chainpad-crypto": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-crypto/-/chainpad-crypto-0.2.8.tgz",
|
||||
"integrity": "sha512-B0/aW0TUcRQUF8Aaz7bBFfIPs/ybdr92Rl0ezVrSxEQuxaRHBNGJrUvVxdKreLuh+XYdbQeeRKDXbgvEcLDcEg==",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-crypto/-/chainpad-crypto-0.3.0.tgz",
|
||||
"integrity": "sha512-L6gUiE8m/ZrUE3eVMju6qzG92Mis3M4T1xCuxVF3eqwa9+46fl9OFwt/TiSmi+oVHSIBmgDTcnOEF/JSxnxYxw==",
|
||||
"license": "AGPL-3.0+",
|
||||
"dependencies": {
|
||||
"tweetnacl": "~0.12.2"
|
||||
"tweetnacl": "^1.0.3",
|
||||
"tweetnacl-util": "^0.15.1"
|
||||
}
|
||||
},
|
||||
"node_modules/chainpad-listmap": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-listmap/-/chainpad-listmap-1.1.1.tgz",
|
||||
"integrity": "sha512-SXb3iJqWyp2wOMa9FT4kqOuR1KgjMPcNCzLlYignu1GdxMI67ZDGTLDucmht4CD8yuYzUWzWmJgs1vs/acH+rw==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-listmap/-/chainpad-listmap-1.2.0.tgz",
|
||||
"integrity": "sha512-PI7iwk/yKzEb1iaVmLKvMJYXjCjvIgUWzI07LeDGVvZPScnYbEzMso9YMQyxzjqrp8cyQxsL7sA8c/hZAz01cw==",
|
||||
"license": "AGPL-3.0+",
|
||||
"dependencies": {
|
||||
"chainpad-netflux": "^1.2.0",
|
||||
"chainpad-netflux": "^1.3.0",
|
||||
"json.sortify": "~2.1.0"
|
||||
}
|
||||
},
|
||||
@ -1927,12 +1932,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/chainpad-netflux": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-netflux/-/chainpad-netflux-1.2.2.tgz",
|
||||
"integrity": "sha512-fcKugW29BE4wo4l3WYLc56yeFznu15bGi6tU3uPtsLGSExXGqNwS+3kmpzI0AFAsuoI0OKPeT4uLX4YzKT/D+A==",
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chainpad-netflux/-/chainpad-netflux-1.3.0.tgz",
|
||||
"integrity": "sha512-oc47vLt78a/Fp7acQJvLNuX1JRrH9oOWAbzo+yOO1asCWDuI4oesPY81wHzVySKpo58GGfNpZN7CSTI8EZjYrQ==",
|
||||
"license": "LGPL-2.1",
|
||||
"dependencies": {
|
||||
"netflux-websocket": "^1.2.0"
|
||||
"netflux-websocket": "^1.2.0",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"tweetnacl-util": "^0.15.1"
|
||||
}
|
||||
},
|
||||
"node_modules/chainpad-server": {
|
||||
@ -2060,6 +2067,22 @@
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
|
||||
},
|
||||
"node_modules/connect-gzip-static": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/connect-gzip-static/-/connect-gzip-static-4.2.1.tgz",
|
||||
"integrity": "sha512-6qC1NYUEZU6mftg2gPspcoPjgBzADm+fB1fPXu3RxBVe59P/Q9HQGQEHnuDaGRDJUoJwl5NX2OgoaaZp7RdpfQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "~2||~3||~4",
|
||||
"mime-types": "~2",
|
||||
"parseurl": "~1",
|
||||
"send": "~0 || ~1",
|
||||
"serve-static": "~1 || ~2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 20.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@ -3267,9 +3290,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/http-proxy-middleware": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz",
|
||||
"integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==",
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz",
|
||||
"integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/http-proxy": "^1.17.15",
|
||||
"debug": "^4.3.6",
|
||||
@ -4186,9 +4210,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/netflux-websocket": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-1.2.1.tgz",
|
||||
"integrity": "sha512-8oQOyEyh0MCnifNIfyvkNXpEELlVRzDleRivRgsDGh+5ZDG109axweVZ0RIOIpkQmTZk4/xVsBk/oLXpMSWEOw=="
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-1.2.2.tgz",
|
||||
"integrity": "sha512-sroG7pBW4QctLtgW55eYNLfzXTbwHBTp7jMXBcY2Dk043PFBL+dpymVgJJWvb2EEbxGFFoaoqc6a8M9w1hIYMQ==",
|
||||
"license": "LGPL-2.1"
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.18",
|
||||
@ -6149,8 +6174,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"resolved": "src/tweetnacl",
|
||||
"link": true
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/tweetnacl-util": {
|
||||
"version": "0.15.1",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz",
|
||||
"integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
@ -6497,10 +6530,6 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"src/tweetnacl": {
|
||||
"version": "0.12.2",
|
||||
"license": "Public domain"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
package.json
12
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "cryptpad",
|
||||
"description": "a collaborative office suite that is end-to-end encrypted and open-source",
|
||||
"version": "2025.3.0",
|
||||
"version": "2025.3.1",
|
||||
"license": "AGPL-3.0+",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -19,13 +19,14 @@
|
||||
"bootstrap": "^4.0.0",
|
||||
"bootstrap-tokenfield": "^0.12.0",
|
||||
"chainpad": "^5.2.6",
|
||||
"chainpad-crypto": "^0.2.5",
|
||||
"chainpad-listmap": "^1.1.1",
|
||||
"chainpad-netflux": "^1.2.2",
|
||||
"chainpad-crypto": "^0.3.0",
|
||||
"chainpad-listmap": "^1.2.0",
|
||||
"chainpad-netflux": "^1.3.0",
|
||||
"chainpad-server": "^5.2.4",
|
||||
"ckeditor": "npm:ckeditor4@~4.22.1",
|
||||
"codemirror": "^5.19.0",
|
||||
"components-font-awesome": "^4.6.3",
|
||||
"connect-gzip-static": "^4.2.1",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"croppie": "^2.5.0",
|
||||
"dragula": "3.7.2",
|
||||
@ -61,7 +62,8 @@
|
||||
"sortify": "^1.0.4",
|
||||
"stream-to-pull-stream": "^1.7.2",
|
||||
"thirty-two": "^1.0.2",
|
||||
"tweetnacl": "file:./src/tweetnacl",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"tweetnacl-util": "^0.15.1",
|
||||
"ulimit": "0.0.2",
|
||||
"ws": "^8.17.1",
|
||||
"x2js": "^3.4.4"
|
||||
|
||||
@ -36,7 +36,10 @@ getApi('config', ApiConfig => {
|
||||
Messages,
|
||||
Broadcast
|
||||
}).then((store) => {
|
||||
console.log(store);
|
||||
console.log('API added to global "CP"');
|
||||
const api = globalThis.CP = store.api;
|
||||
const cfg = { channel: '0123456789abcdef0123456789abcedf' };
|
||||
api.pad.join(cfg, console.log);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -7,6 +7,7 @@ const nThen = require('nthen');
|
||||
const Nacl = require('tweetnacl/nacl-fast');
|
||||
const Path = require('path');
|
||||
const Pins = require('../lib/pins');
|
||||
const Util = require('../lib/common-util');
|
||||
const Config = require('../lib/load-config');
|
||||
|
||||
var escapeKeyCharacters = function (key) {
|
||||
@ -24,9 +25,9 @@ if (dataIdx === -1) {
|
||||
const deleteData = JSON.parse(process.argv[dataIdx+1]);
|
||||
if (!deleteData.toSign || !deleteData.proof) { return void console.error("Invalid arguments"); }
|
||||
// Check sig
|
||||
const ed = Nacl.util.decodeBase64(deleteData.toSign.edPublic);
|
||||
const signed = Nacl.util.decodeUTF8(JSON.stringify(deleteData.toSign));
|
||||
const proof = Nacl.util.decodeBase64(deleteData.proof);
|
||||
const ed = Util.decodeBase64(deleteData.toSign.edPublic);
|
||||
const signed = Util.decodeUTF8(JSON.stringify(deleteData.toSign));
|
||||
const proof = Util.decodeBase64(deleteData.proof);
|
||||
if (!Nacl.sign.detached.verify(signed, proof, ed)) { return void console.error("Invalid signature"); }
|
||||
edPublic = escapeKeyCharacters(deleteData.toSign.edPublic);
|
||||
}
|
||||
@ -43,7 +44,7 @@ nThen((waitFor) => {
|
||||
pinned = Pins.calculateFromLog(content.toString('utf8'), f);
|
||||
}));
|
||||
}).nThen((waitFor) => {
|
||||
Pins.list(waitFor((err, d) => {
|
||||
Pins.load(waitFor((err, d) => {
|
||||
data = Object.keys(d);
|
||||
}), {
|
||||
exclude: [edPublic + '.ndjson']
|
||||
|
||||
@ -20,7 +20,6 @@ var compare = function () {
|
||||
Pins.list(w(function (err, p) {
|
||||
if (err) { throw err; }
|
||||
list = p;
|
||||
console.log(p);
|
||||
console.log(list);
|
||||
console.log();
|
||||
}), conf);
|
||||
|
||||
@ -34,6 +34,7 @@ Fse.rmSync(oldComponentsPath, { recursive: true, force: true });
|
||||
"mathjax",
|
||||
"open-sans-fontface",
|
||||
"tweetnacl",
|
||||
"tweetnacl-util",
|
||||
"require-css",
|
||||
"requirejs",
|
||||
"requirejs-plugins",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
const Nacl = require('tweetnacl/nacl-fast');
|
||||
const Util = require('../lib/common-util');
|
||||
|
||||
const keyPair = Nacl.box.keyPair();
|
||||
console.log("You've just generated a new key pair for your support mailbox.");
|
||||
@ -19,9 +20,9 @@ console.log("NOTE: You can change the key pair at any time if you want to revoke
|
||||
console.log();
|
||||
console.log();
|
||||
console.log("Your public key (add it to config.js):");
|
||||
console.log(Nacl.util.encodeBase64(keyPair.publicKey));
|
||||
console.log(Util.encodeBase64(keyPair.publicKey));
|
||||
|
||||
console.log();
|
||||
console.log();
|
||||
console.log("Your private key (store it in a safe place and send it to your instance's admins):");
|
||||
console.log(Nacl.util.encodeBase64(keyPair.secretKey));
|
||||
console.log(Util.encodeBase64(keyPair.secretKey));
|
||||
|
||||
@ -5,13 +5,14 @@
|
||||
let SodiumNative = require('sodium-native');
|
||||
let Nacl = require('tweetnacl/nacl-fast');
|
||||
let LibSodium = require('libsodium-wrappers');
|
||||
let Util = require('../lib/common-util');
|
||||
|
||||
|
||||
let msgStr = "This is a test";
|
||||
let keys = Nacl.sign.keyPair();
|
||||
let pub = keys.publicKey;
|
||||
|
||||
let msg = Nacl.util.decodeUTF8(msgStr);
|
||||
let msg = Util.decodeUTF8(msgStr);
|
||||
let signedMsg = Nacl.sign(msg, keys.secretKey);
|
||||
let sig = signedMsg.subarray(0, 64);
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ var Nacl = require("tweetnacl/nacl-fast");
|
||||
var nThen = require("nthen");
|
||||
var CPNetflux = require("../../www/components/chainpad-netflux/chainpad-netflux");
|
||||
var Hash = require("../../www/common/common-hash");
|
||||
var Util = require("../../lib/common-util");
|
||||
var Rpc = require("../../www/common/rpc");
|
||||
var HK = require("../../lib/hk-util");
|
||||
|
||||
@ -69,7 +70,7 @@ nThen(function (w) {
|
||||
//console.log(i);
|
||||
if (i-- <= 0) { return void done(); }
|
||||
|
||||
var ciphertext = Nacl.util.encodeBase64(Nacl.randomBytes(256));
|
||||
var ciphertext = Util.encodeBase64(Nacl.randomBytes(256));
|
||||
|
||||
client.anonRpc.send('WRITE_PRIVATE_MESSAGE', [
|
||||
client.channel,
|
||||
|
||||
@ -55,16 +55,16 @@ var state = {};
|
||||
var makeCurveKeys = function () {
|
||||
var pair = Nacl.box.keyPair();
|
||||
return {
|
||||
curvePrivate: Nacl.util.encodeBase64(pair.secretKey),
|
||||
curvePublic: Nacl.util.encodeBase64(pair.publicKey),
|
||||
curvePrivate: Util.encodeBase64(pair.secretKey),
|
||||
curvePublic: Util.encodeBase64(pair.publicKey),
|
||||
};
|
||||
};
|
||||
|
||||
var makeEdKeys = function () {
|
||||
var keys = Nacl.sign.keyPair.fromSeed(Nacl.randomBytes(Nacl.sign.seedLength));
|
||||
return {
|
||||
edPrivate: Nacl.util.encodeBase64(keys.secretKey),
|
||||
edPublic: Nacl.util.encodeBase64(keys.publicKey),
|
||||
edPrivate: Util.encodeBase64(keys.secretKey),
|
||||
edPublic: Util.encodeBase64(keys.publicKey),
|
||||
};
|
||||
};
|
||||
|
||||
@ -198,7 +198,7 @@ nThen(function (w) {
|
||||
alice.anonRpc.send('WRITE_PRIVATE_MESSAGE', [
|
||||
alice.mailboxChannel,
|
||||
msg
|
||||
//Nacl.util.encodeBase64(Nacl.randomBytes(128))
|
||||
//Util.encodeBase64(Nacl.randomBytes(128))
|
||||
], w(function (err) {
|
||||
if (err) { throw new Error(err); }
|
||||
console.log('message %s written successfully', i);
|
||||
|
||||
@ -33,7 +33,7 @@ var handler = function (ref, id /* safeKey */, pinned) {
|
||||
//console.log(ref, id);
|
||||
};
|
||||
|
||||
Pins.list(function (err) {
|
||||
Pins.load(function (err) {
|
||||
if (err) { return void console.error(err); }
|
||||
/*
|
||||
for (var id in pinned) {
|
||||
|
||||
@ -43,16 +43,16 @@ process.on('unhandledRejection', function (err) {
|
||||
var makeCurveKeys = function () {
|
||||
var pair = Nacl.box.keyPair();
|
||||
return {
|
||||
curvePrivate: Nacl.util.encodeBase64(pair.secretKey),
|
||||
curvePublic: Nacl.util.encodeBase64(pair.publicKey),
|
||||
curvePrivate: Util.encodeBase64(pair.secretKey),
|
||||
curvePublic: Util.encodeBase64(pair.publicKey),
|
||||
};
|
||||
};
|
||||
|
||||
var makeEdKeys = function () {
|
||||
var keys = Nacl.sign.keyPair.fromSeed(Nacl.randomBytes(Nacl.sign.seedLength));
|
||||
return {
|
||||
edPrivate: Nacl.util.encodeBase64(keys.secretKey),
|
||||
edPublic: Nacl.util.encodeBase64(keys.publicKey),
|
||||
edPrivate: Util.encodeBase64(keys.secretKey),
|
||||
edPublic: Util.encodeBase64(keys.publicKey),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -9,13 +9,13 @@ var factory = function (Util, Crypto, Keys, Nacl) {
|
||||
var uint8ArrayToHex = Util.uint8ArrayToHex;
|
||||
var hexToBase64 = Util.hexToBase64;
|
||||
var base64ToHex = Util.base64ToHex;
|
||||
Hash.encodeBase64 = Nacl.util.encodeBase64;
|
||||
Hash.decodeBase64 = Nacl.util.decodeBase64;
|
||||
Hash.encodeBase64 = Util.encodeBase64;
|
||||
Hash.decodeBase64 = Util.decodeBase64;
|
||||
|
||||
// This implementation must match that on the server
|
||||
// it's used for a checksum
|
||||
Hash.hashChannelList = function (list) {
|
||||
return Nacl.util.encodeBase64(Nacl.hash(Nacl.util
|
||||
return Util.encodeBase64(Nacl.hash(Util
|
||||
.decodeUTF8(JSON.stringify(list))));
|
||||
};
|
||||
|
||||
@ -34,15 +34,15 @@ var factory = function (Util, Crypto, Keys, Nacl) {
|
||||
|
||||
Hash.getSignPublicFromPrivate = function (edPrivateSafeStr) {
|
||||
var edPrivateStr = Crypto.b64AddSlashes(edPrivateSafeStr);
|
||||
var privateKey = Nacl.util.decodeBase64(edPrivateStr);
|
||||
var privateKey = Util.decodeBase64(edPrivateStr);
|
||||
var keyPair = Nacl.sign.keyPair.fromSecretKey(privateKey);
|
||||
return Nacl.util.encodeBase64(keyPair.publicKey);
|
||||
return Util.encodeBase64(keyPair.publicKey);
|
||||
};
|
||||
Hash.getCurvePublicFromPrivate = function (curvePrivateSafeStr) {
|
||||
var curvePrivateStr = Crypto.b64AddSlashes(curvePrivateSafeStr);
|
||||
var privateKey = Nacl.util.decodeBase64(curvePrivateStr);
|
||||
var privateKey = Util.decodeBase64(curvePrivateStr);
|
||||
var keyPair = Nacl.box.keyPair.fromSecretKey(privateKey);
|
||||
return Nacl.util.encodeBase64(keyPair.publicKey);
|
||||
return Util.encodeBase64(keyPair.publicKey);
|
||||
};
|
||||
|
||||
var getEditHashFromKeys = Hash.getEditHashFromKeys = function (secret) {
|
||||
@ -585,7 +585,7 @@ Version 4: Data URL when not a realtime link yet (new pad or "static" app)
|
||||
secret.channel = base64ToHex(parsed.channel);
|
||||
secret.keys = {
|
||||
fileKeyStr: parsed.key,
|
||||
cryptKey: Nacl.util.decodeBase64(parsed.key)
|
||||
cryptKey: Util.decodeBase64(parsed.key)
|
||||
};
|
||||
} else if (parsed.type === "user") {
|
||||
throw new Error("User hashes can't be opened (yet)");
|
||||
@ -653,15 +653,15 @@ Version 4: Data URL when not a realtime link yet (new pad or "static" app)
|
||||
var keys = secret && secret.keys;
|
||||
var secondary = keys && keys.secondaryKey;
|
||||
if (!secondary) { return; }
|
||||
var curvePair = Nacl.box.keyPair.fromSecretKey(Nacl.util.decodeUTF8(secondary).slice(0,32));
|
||||
var curvePair = Nacl.box.keyPair.fromSecretKey(Util.decodeUTF8(secondary).slice(0,32));
|
||||
var ret = {};
|
||||
ret.form_public = Nacl.util.encodeBase64(curvePair.publicKey);
|
||||
var privateKey = ret.form_private = Nacl.util.encodeBase64(curvePair.secretKey);
|
||||
ret.form_public = Util.encodeBase64(curvePair.publicKey);
|
||||
var privateKey = ret.form_private = Util.encodeBase64(curvePair.secretKey);
|
||||
|
||||
var auditorHash = Hash.getViewHashFromKeys({
|
||||
version: 1,
|
||||
channel: secret.channel,
|
||||
keys: { viewKeyStr: Nacl.util.encodeBase64(keys.cryptKey) }
|
||||
keys: { viewKeyStr: Util.encodeBase64(keys.cryptKey) }
|
||||
});
|
||||
var _parsed = Hash.parseTypeHash('pad', auditorHash);
|
||||
ret.form_auditorHash = _parsed.getHash({auditorKey: privateKey});
|
||||
@ -720,12 +720,12 @@ Version 4: Data URL when not a realtime link yet (new pad or "static" app)
|
||||
|
||||
Hash.decodeDataOptions = function (opts) {
|
||||
var b64 = decodeURIComponent(opts);
|
||||
var str = Nacl.util.encodeUTF8(Nacl.util.decodeBase64(b64));
|
||||
var str = Util.encodeUTF8(Util.decodeBase64(b64));
|
||||
return Util.tryParse(str) || {};
|
||||
};
|
||||
Hash.encodeDataOptions = function (opts) {
|
||||
var str = JSON.stringify(opts);
|
||||
var b64 = Nacl.util.encodeBase64(Nacl.util.decodeUTF8(str));
|
||||
var b64 = Util.encodeBase64(Util.decodeUTF8(str));
|
||||
return encodeURIComponent(b64);
|
||||
};
|
||||
Hash.getNewPadURL = function (href, opts) {
|
||||
|
||||
@ -1,161 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
(() => {
|
||||
const factory = (Crypto, Hash, Util, Constants, Realtime) => {
|
||||
var Msg = {};
|
||||
|
||||
var createData = Msg.createData = function (proxy, hash) {
|
||||
var data = {
|
||||
channel: hash || Hash.createChannelId(),
|
||||
displayName: proxy['cryptpad.username'],
|
||||
profile: proxy.profile && proxy.profile.view,
|
||||
edPublic: proxy.edPublic,
|
||||
curvePublic: proxy.curvePublic,
|
||||
notifications: Util.find(proxy, ['mailboxes', 'notifications', 'channel']),
|
||||
avatar: proxy.profile && proxy.profile.avatar,
|
||||
uid: proxy.uid,
|
||||
};
|
||||
if (hash === false) { delete data.channel; }
|
||||
return data;
|
||||
};
|
||||
|
||||
var getFriend = Msg.getFriend = function (proxy, pubkey) {
|
||||
if (!pubkey) { return; }
|
||||
if (pubkey === proxy.curvePublic) {
|
||||
var data = createData(proxy);
|
||||
delete data.channel;
|
||||
return data;
|
||||
}
|
||||
return proxy.friends ? proxy.friends[pubkey] : undefined;
|
||||
};
|
||||
|
||||
var getFriendList = Msg.getFriendList = function (proxy) {
|
||||
if (!proxy.friends) { proxy.friends = {}; }
|
||||
return proxy.friends;
|
||||
};
|
||||
|
||||
var eachFriend = function (friends, cb) {
|
||||
Object.keys(friends).forEach(function (id) {
|
||||
if (id === 'me') { return; }
|
||||
cb(friends[id], id, friends);
|
||||
});
|
||||
};
|
||||
|
||||
Msg.getFriendChannelsList = function (proxy) {
|
||||
var list = [];
|
||||
eachFriend(proxy.friends, function (friend) {
|
||||
list.push(friend.channel);
|
||||
});
|
||||
return list;
|
||||
};
|
||||
|
||||
Msg.declineFriendRequest = function (store, data, cb) {
|
||||
store.mailbox.sendTo('DECLINE_FRIEND_REQUEST', {}, {
|
||||
channel: data.notifications,
|
||||
curvePublic: data.curvePublic
|
||||
}, function (obj) {
|
||||
cb(obj);
|
||||
});
|
||||
};
|
||||
Msg.acceptFriendRequest = function (store, data, cb) {
|
||||
var friend = getFriend(store.proxy, data.curvePublic) || {};
|
||||
var myData = createData(store.proxy, friend.channel || data.channel);
|
||||
store.mailbox.sendTo('ACCEPT_FRIEND_REQUEST', { user: myData }, {
|
||||
channel: data.notifications,
|
||||
curvePublic: data.curvePublic
|
||||
}, function (obj) {
|
||||
cb(obj);
|
||||
});
|
||||
};
|
||||
Msg.addToFriendList = function (cfg, data, cb) {
|
||||
var proxy = cfg.proxy;
|
||||
var friends = getFriendList(proxy);
|
||||
var pubKey = data.curvePublic; // todo validata data
|
||||
|
||||
if (pubKey === proxy.curvePublic) { return void cb("E_MYKEY"); }
|
||||
|
||||
friends[pubKey] = data;
|
||||
|
||||
Realtime.whenRealtimeSyncs(cfg.realtime, function () {
|
||||
cb();
|
||||
cfg.pinPads([data.channel], function (res) {
|
||||
if (res.error) { console.error(res.error); }
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Msg.updateMyData = function (store, curve) {
|
||||
var myData = createData(store.proxy, false);
|
||||
if (store.proxy.friends) {
|
||||
store.proxy.friends.me = Util.clone(myData);
|
||||
delete store.proxy.friends.me.channel;
|
||||
}
|
||||
if (store.modules['team']) {
|
||||
store.modules['team'].updateMyData(myData);
|
||||
}
|
||||
var todo = function (friend) {
|
||||
if (!friend || !friend.notifications) { return; }
|
||||
delete friend.user;
|
||||
myData.channel = friend.channel;
|
||||
store.mailbox.sendTo('UPDATE_DATA', myData, {
|
||||
channel: friend.notifications,
|
||||
curvePublic: friend.curvePublic
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) { console.error(obj); }
|
||||
});
|
||||
};
|
||||
if (curve) {
|
||||
var friend = getFriend(store.proxy, curve);
|
||||
return void todo(friend);
|
||||
}
|
||||
eachFriend(store.proxy.friends || {}, todo);
|
||||
};
|
||||
|
||||
Msg.removeFriend = function (store, curvePublic, cb) {
|
||||
var proxy = store.proxy;
|
||||
var friend = proxy.friends[curvePublic];
|
||||
if (!friend) { return void cb({error: 'ENOENT'}); }
|
||||
if (!friend.notifications) { return void cb({error: 'EINVAL'}); }
|
||||
|
||||
store.mailbox.sendTo('UNFRIEND', {
|
||||
curvePublic: proxy.curvePublic
|
||||
}, {
|
||||
channel: friend.notifications,
|
||||
curvePublic: friend.curvePublic
|
||||
}, function (obj) {
|
||||
if (obj && obj.error) {
|
||||
return void cb(obj);
|
||||
}
|
||||
store.messenger.onFriendRemoved(curvePublic, friend.channel);
|
||||
delete proxy.friends[curvePublic];
|
||||
Realtime.whenRealtimeSyncs(store.realtime, function () {
|
||||
cb(obj);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return Msg;
|
||||
};
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = factory(
|
||||
require('chainpad-crypto'),
|
||||
require('./common-hash'),
|
||||
require('./common-util'),
|
||||
require('./common-constants'),
|
||||
require('./common-realtime')
|
||||
);
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
define([
|
||||
'/components/chainpad-crypto/crypto.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/common-constants.js',
|
||||
'/common/common-realtime.js',
|
||||
], factory);
|
||||
} else {
|
||||
// unsupported initialization
|
||||
}
|
||||
})();
|
||||
@ -3,12 +3,22 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
(function (window) {
|
||||
var Util = {};
|
||||
const factory = (NaclUtil) => {
|
||||
var Util = window.CryptPad_Util = {};
|
||||
|
||||
// polyfill for atob in case you're using this from node...
|
||||
window.atob = window.atob || function (str) { return Buffer.from(str, 'base64').toString('binary'); };
|
||||
window.btoa = window.btoa || function (str) { return Buffer.from(str, 'binary').toString('base64'); };
|
||||
|
||||
Util.encodeBase64 = NaclUtil.encodeBase64;
|
||||
Util.decodeBase64 = str => {
|
||||
let i = str.length % 4;
|
||||
if (i) { str += '='.repeat(4-i); }
|
||||
return NaclUtil.decodeBase64(str);
|
||||
};
|
||||
Util.encodeUTF8 = NaclUtil.encodeUTF8;
|
||||
Util.decodeUTF8 = NaclUtil.decodeUTF8;
|
||||
|
||||
Util.slice = function (A, start, end) {
|
||||
return Array.prototype.slice.call(A, start, end);
|
||||
};
|
||||
@ -857,14 +867,16 @@
|
||||
};
|
||||
/* End of code copied from saferphore */
|
||||
|
||||
return Util;
|
||||
};
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = Util;
|
||||
module.exports = factory(require('tweetnacl-util'));
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
define([], function () {
|
||||
window.CryptPad_Util = Util;
|
||||
return Util;
|
||||
define(['/components/tweetnacl-util/nacl-util.min.js'], function () {
|
||||
return factory(globalThis?.nacl?.util);
|
||||
});
|
||||
} else {
|
||||
window.CryptPad_Util = Util;
|
||||
// Unsupported initialization
|
||||
}
|
||||
}(typeof(self) !== 'undefined'? self: this));
|
||||
|
||||
@ -225,8 +225,8 @@ if (typeof(module) !== 'undefined' && module.exports) {
|
||||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-realtime.js',
|
||||
'/common/outer/network-config.js',
|
||||
'/common/outer/cache-store.js',
|
||||
'/common/network-config.js',
|
||||
'/common/cache-store.js',
|
||||
'/common/pinpad.js',
|
||||
'/components/nthen/index.js',
|
||||
'/components/chainpad/chainpad.dist.js',
|
||||
|
||||
@ -1,130 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
(() => {
|
||||
const factory = (nThen, Util, ApiConfig = {}, Nacl) => {
|
||||
|
||||
const getApiOrigin = function () {
|
||||
if (!Object.keys(ApiConfig).length) { return; }
|
||||
var url;
|
||||
var unsafeOriginURL = new URL(ApiConfig.httpUnsafeOrigin);
|
||||
try {
|
||||
url = new URL(ApiConfig.websocketPath, ApiConfig.httpUnsafeOrigin);
|
||||
url.protocol = unsafeOriginURL.protocol;
|
||||
return url.origin;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return ApiConfig.httpUnsafeOrigin;
|
||||
}
|
||||
};
|
||||
var API_ORIGIN = getApiOrigin();
|
||||
|
||||
const setCustomize = data => {
|
||||
ApiConfig = data.ApiConfig;
|
||||
API_ORIGIN = getApiOrigin();
|
||||
};
|
||||
|
||||
var clone = o => JSON.parse(JSON.stringify(o));
|
||||
var randomToken = () => Nacl.util.encodeBase64(Nacl.randomBytes(24));
|
||||
var postData = function (url, data, cb) {
|
||||
var CB = Util.once(Util.mkAsync(cb));
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
|
||||
return void response.text().then(result => { CB(void 0, Util.tryParse(result)); }); // checkup error when using .json()
|
||||
//return void response.json().then(result => { CB(void 0, result); });
|
||||
}
|
||||
|
||||
response.json().then().then(result => {
|
||||
CB(response.status, result);
|
||||
});
|
||||
//CB(response.status, response);
|
||||
}).catch(error => {
|
||||
CB(error);
|
||||
});
|
||||
};
|
||||
|
||||
var serverCommand = function (keypair, my_data, cb) {
|
||||
var obj = clone(my_data);
|
||||
obj.publicKey = Nacl.util.encodeBase64(keypair.publicKey);
|
||||
obj.nonce = randomToken();
|
||||
var href = new URL('/api/auth/', API_ORIGIN);
|
||||
var txid, date;
|
||||
nThen(function (w) {
|
||||
// Tell the server we want to do some action
|
||||
postData(href, obj, w((err, data) => {
|
||||
if (err) {
|
||||
w.abort();
|
||||
console.error(err);
|
||||
// there might be more info here
|
||||
if (data) { console.error(data); }
|
||||
return void cb(err);
|
||||
}
|
||||
|
||||
// if the requested action is valid, it responds with a txid and a nonce
|
||||
// bundle all that up into an object, stringify it, and sign it.
|
||||
// respond with an object: {sig, txid}
|
||||
if (!data.date || !data.txid) {
|
||||
w.abort();
|
||||
return void cb('REQUEST_REJECTED');
|
||||
}
|
||||
txid = data.txid;
|
||||
date = data.date;
|
||||
}));
|
||||
}).nThen(function (w) {
|
||||
var copy = clone(obj);
|
||||
copy.txid = txid;
|
||||
copy.date = date;
|
||||
var toSign = Nacl.util.decodeUTF8(JSON.stringify(copy));
|
||||
var sig = Nacl.sign.detached(toSign, keypair.secretKey);
|
||||
var encoded = Nacl.util.encodeBase64(sig);
|
||||
var obj2 = {
|
||||
sig: encoded,
|
||||
txid: txid,
|
||||
};
|
||||
postData(href, obj2, w((err, data) => {
|
||||
if (err) {
|
||||
w.abort();
|
||||
console.error(err);
|
||||
// there might be more info here
|
||||
if (data) { console.error(data); }
|
||||
return void cb("RESPONSE_REJECTED", data);
|
||||
}
|
||||
cb(void 0, data);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
serverCommand.setCustomize = setCustomize;
|
||||
|
||||
return serverCommand;
|
||||
};
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = factory(
|
||||
require('nthen'),
|
||||
require('./common-util'),
|
||||
undefined,
|
||||
require('tweetnacl/nacl-fast')
|
||||
);
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
define([
|
||||
'/components/nthen/index.js',
|
||||
'/common/common-util.js',
|
||||
'/api/config',
|
||||
'/components/tweetnacl/nacl-fast.min.js',
|
||||
], (nThen, Util, ApiConfig) => {
|
||||
return factory(nThen, Util, ApiConfig, window.nacl);
|
||||
});
|
||||
} else {
|
||||
// unsupported initialization
|
||||
}
|
||||
|
||||
})();
|
||||
@ -14,7 +14,7 @@ const factory = (ApiConfig = {}) => {
|
||||
var path = ApiConfig.websocketPath || '/cryptpad_websocket';
|
||||
if (/^ws{1,2}:\/\//.test(path)) { return path; }
|
||||
|
||||
var l = new URL(origin || self?.location?.href);
|
||||
var l = new URL(origin || globalThis?.location?.href || ApiConfig.httpUnsafeOrigin);
|
||||
if (origin) {
|
||||
l.href = origin;
|
||||
}
|
||||
|
||||
@ -4,8 +4,10 @@
|
||||
|
||||
(() => {
|
||||
const factory = () => {
|
||||
const version = 8;
|
||||
return {
|
||||
currentVersion: 'v7'
|
||||
currentVersionNumber: version,
|
||||
currentVersion: 'v' + version
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ const factory = (nThen, Util, ApiConfig = {}, Nacl) => {
|
||||
};
|
||||
|
||||
var clone = o => JSON.parse(JSON.stringify(o));
|
||||
var randomToken = () => Nacl.util.encodeBase64(Nacl.randomBytes(24));
|
||||
var randomToken = () => Util.encodeBase64(Nacl.randomBytes(24));
|
||||
var postData = function (url, data, cb) {
|
||||
var CB = Util.once(Util.mkAsync(cb));
|
||||
fetch(url, {
|
||||
@ -53,7 +53,7 @@ const factory = (nThen, Util, ApiConfig = {}, Nacl) => {
|
||||
|
||||
var serverCommand = function (keypair, my_data, cb) {
|
||||
var obj = clone(my_data);
|
||||
obj.publicKey = Nacl.util.encodeBase64(keypair.publicKey);
|
||||
obj.publicKey = Util.encodeBase64(keypair.publicKey);
|
||||
obj.nonce = randomToken();
|
||||
var href = new URL('/api/auth/', API_ORIGIN);
|
||||
var txid, date;
|
||||
@ -82,9 +82,9 @@ const factory = (nThen, Util, ApiConfig = {}, Nacl) => {
|
||||
var copy = clone(obj);
|
||||
copy.txid = txid;
|
||||
copy.date = date;
|
||||
var toSign = Nacl.util.decodeUTF8(JSON.stringify(copy));
|
||||
var toSign = Util.decodeUTF8(JSON.stringify(copy));
|
||||
var sig = Nacl.sign.detached(toSign, keypair.secretKey);
|
||||
var encoded = Nacl.util.encodeBase64(sig);
|
||||
var encoded = Util.encodeBase64(sig);
|
||||
var obj2 = {
|
||||
sig: encoded,
|
||||
txid: txid,
|
||||
@ -110,7 +110,7 @@ const factory = (nThen, Util, ApiConfig = {}, Nacl) => {
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = factory(
|
||||
require('nthen'),
|
||||
require('./common-util'),
|
||||
require('../common-util'),
|
||||
undefined,
|
||||
require('tweetnacl/nacl-fast')
|
||||
);
|
||||
@ -23,7 +23,7 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
// [b64_public, b64_sig, b64_block [version, nonce, content]]
|
||||
|
||||
Block.seed = function () {
|
||||
return Nacl.hash(Nacl.util.decodeUTF8('pewpewpew'));
|
||||
return Nacl.hash(Util.decodeUTF8('pewpewpew'));
|
||||
};
|
||||
|
||||
// should be deterministic from a seed...
|
||||
@ -49,8 +49,8 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
try {
|
||||
var sign = keys.sign;
|
||||
return {
|
||||
edPrivate: Nacl.util.encodeBase64(sign.secretKey),
|
||||
edPublic: Nacl.util.encodeBase64(sign.publicKey),
|
||||
edPrivate: Util.encodeBase64(sign.secretKey),
|
||||
edPublic: Util.encodeBase64(sign.publicKey),
|
||||
};
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@ -60,7 +60,7 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
|
||||
// (UTF8 content, keys object) => Uint8Array block
|
||||
Block.encrypt = function (version, content, keys) {
|
||||
var u8 = Nacl.util.decodeUTF8(content);
|
||||
var u8 = Util.decodeUTF8(content);
|
||||
var nonce = Nacl.randomBytes(Nacl.secretbox.nonceLength);
|
||||
return Block.join([
|
||||
[0],
|
||||
@ -77,7 +77,7 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
|
||||
var plaintext = Nacl.secretbox.open(box, nonce, keys.symmetric);
|
||||
try {
|
||||
return JSON.parse(Nacl.util.encodeUTF8(plaintext));
|
||||
return JSON.parse(Util.encodeUTF8(plaintext));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return;
|
||||
@ -98,9 +98,9 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
|
||||
// serialize {publickey, sig, ciphertext}
|
||||
return {
|
||||
publicKey: Nacl.util.encodeBase64(keys.sign.publicKey),
|
||||
signature: Nacl.util.encodeBase64(sig),
|
||||
ciphertext: Nacl.util.encodeBase64(ciphertext),
|
||||
publicKey: Util.encodeBase64(keys.sign.publicKey),
|
||||
signature: Util.encodeBase64(sig),
|
||||
ciphertext: Util.encodeBase64(ciphertext),
|
||||
};
|
||||
};
|
||||
|
||||
@ -111,14 +111,14 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
// sign your old publicKey with your old privateKey
|
||||
var u8_sig = Nacl.sign.detached(u8_pub, u8_secret);
|
||||
// return an array with the sig and the pubkey
|
||||
return JSON.stringify([u8_pub, u8_sig].map(Nacl.util.encodeBase64));
|
||||
return JSON.stringify([u8_pub, u8_sig].map(Util.encodeBase64));
|
||||
} catch (err) {
|
||||
return void console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
var urlSafeB64 = function (u8) {
|
||||
return Nacl.util.encodeBase64(u8).replace(/\//g, '-');
|
||||
return Util.encodeBase64(u8).replace(/\//g, '-');
|
||||
};
|
||||
|
||||
Block.getBlockUrl = function (keys) {
|
||||
@ -138,7 +138,7 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
|
||||
var decodeSafeB64 = function (b64) {
|
||||
try {
|
||||
return Nacl.util.decodeBase64(b64.replace(/\-/g, '/'));
|
||||
return Util.decodeBase64(b64.replace(/\-/g, '/'));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return;
|
||||
@ -224,7 +224,7 @@ const factory = (Util, ApiConfig = {}, ServerCommand, Nacl) => {
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = factory(
|
||||
require('./common-util'),
|
||||
require('../common-util'),
|
||||
undefined,
|
||||
require('./http-command'),
|
||||
require('tweetnacl/nacl-fast')
|
||||
@ -27,7 +27,7 @@ const factory = (AppConfig = {}, ApiConfig = {},
|
||||
setCustomize({AppConfig,ApiConfig});
|
||||
}
|
||||
|
||||
const Types = { setCustomize };
|
||||
const Types = { OO_APPS, setCustomize };
|
||||
|
||||
Types.__defineGetter__("availableTypes", function () {
|
||||
if (ApiConfig.appsToDisable) {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
(() => {
|
||||
const factory = (UserObject, Util, Hash,
|
||||
SF, Messages = {}, Feedback, nThen) => {
|
||||
Messages = {}, Feedback, nThen, SF = {}) => {
|
||||
|
||||
let setCustomize = data => {
|
||||
Messages = data.Messages;
|
||||
@ -617,7 +617,7 @@ const factory = (UserObject, Util, Hash,
|
||||
if (data.password) { folderData.password = data.password; }
|
||||
if (data.owned) { folderData.owners = [Env.edPublic]; }
|
||||
}).nThen(function (waitFor) {
|
||||
Env.Store.getPadMetadata(null, {
|
||||
Env.Store.pad.getMetadata(null, {
|
||||
channel: folderData.channel
|
||||
}, waitFor(function (obj) {
|
||||
if (obj && (obj.error || obj.rejected)) {
|
||||
@ -637,7 +637,9 @@ const factory = (UserObject, Util, Hash,
|
||||
var parsed = Hash.parsePadUrl(folderData.href);
|
||||
var secret = Hash.getSecrets('drive', parsed.hash, folderData.password);
|
||||
SF.upgrade(secret.channel, secret);
|
||||
Env.folders[folderId].userObject.setReadOnly(false, secret.keys.secondaryKey);
|
||||
if (Env.folders[folderId]) {
|
||||
Env.folders[folderId].userObject.setReadOnly(false, secret.keys.secondaryKey);
|
||||
}
|
||||
waitFor.abort();
|
||||
return void cb(folderId);
|
||||
}
|
||||
@ -667,7 +669,7 @@ const factory = (UserObject, Util, Hash,
|
||||
}
|
||||
if (data.folderData) {
|
||||
// If we're importing a folder, check its serverside metadata
|
||||
Env.Store.getPadMetadata(null, { channel: folderData.channel }, function (md) {
|
||||
Env.Store.pad.getMetadata(null, { channel: folderData.channel }, function (md) {
|
||||
var fData = Env.user.proxy[UserObject.SHARED_FOLDERS][id];
|
||||
if (md.owners) { fData.owners = md.owners; }
|
||||
if (md.expire) { fData.expire = +md.expire; }
|
||||
@ -1841,20 +1843,20 @@ if (typeof(module) !== 'undefined' && module.exports) {
|
||||
require('./user-object'),
|
||||
require('./common-util'),
|
||||
require('./common-hash'),
|
||||
require('../worker/components/sharedfolder'),
|
||||
undefined,
|
||||
require('./common-feedback'),
|
||||
require('nthen')
|
||||
require('nthen'),
|
||||
require('../worker/components/sharedfolder'),
|
||||
);
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
define([
|
||||
'/common/user-object.js',
|
||||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/outer/sharedfolder.js',
|
||||
'/customize/messages.js',
|
||||
'/common/common-feedback.js',
|
||||
'/components/nthen/index.js',
|
||||
// sharedfolder.js not needed outside of worker
|
||||
], factory);
|
||||
} else {
|
||||
// unsupported initialization
|
||||
|
||||
@ -14,8 +14,8 @@ var factory = function (Util, Nacl) {
|
||||
// we will sign various message with our edPrivate keys
|
||||
// this handles that in a generic way
|
||||
var signMsg = function (data, signKey) {
|
||||
var buffer = Nacl.util.decodeUTF8(JSON.stringify(data));
|
||||
return Nacl.util.encodeBase64(Nacl.sign.detached(buffer, signKey));
|
||||
var buffer = Util.decodeUTF8(JSON.stringify(data));
|
||||
return Util.encodeBase64(Nacl.sign.detached(buffer, signKey));
|
||||
};
|
||||
|
||||
// sendMsg takes a pre-formed message, does a little validation
|
||||
@ -299,7 +299,7 @@ var factory = function (Util, Nacl) {
|
||||
var signKey;
|
||||
|
||||
try {
|
||||
signKey = Nacl.util.decodeBase64(edPrivateKey);
|
||||
signKey = Util.decodeBase64(edPrivateKey);
|
||||
if (signKey.length !== 64) {
|
||||
throw new Error('private key did not match expected length of 64');
|
||||
}
|
||||
@ -308,7 +308,7 @@ var factory = function (Util, Nacl) {
|
||||
}
|
||||
|
||||
try {
|
||||
if (Nacl.util.decodeBase64(edPublicKey).length !== 32) {
|
||||
if (Util.decodeBase64(edPublicKey).length !== 32) {
|
||||
return void cb('expected public key to be 32 uint');
|
||||
}
|
||||
} catch (err) { return void cb(err); }
|
||||
|
||||
1
src/tweetnacl/.gitignore
vendored
1
src/tweetnacl/.gitignore
vendored
@ -1 +0,0 @@
|
||||
node_modules
|
||||
@ -1,3 +0,0 @@
|
||||
test
|
||||
.travis.yml
|
||||
bower.json
|
||||
@ -1,7 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
env:
|
||||
- NACL_SRC=nacl.min.js
|
||||
- NACL_SRC=nacl-fast.min.js
|
||||
script: "npm run testall"
|
||||
@ -1,101 +0,0 @@
|
||||
TweetNaCl.js Changelog
|
||||
======================
|
||||
|
||||
|
||||
v0.12.2
|
||||
-------
|
||||
|
||||
* Improved performance of curve operations, making `nacl.scalarMult`, `nacl.box`,
|
||||
`nacl.sign` and related functions up to 3x faster in `nacl-fast` version.
|
||||
|
||||
|
||||
v0.12.1
|
||||
-------
|
||||
|
||||
* Significantly improved performance of Salsa20 (~1.5x faster) and
|
||||
Poly1305 (~3.5x faster) in `nacl-fast` version.
|
||||
|
||||
|
||||
v0.12.0
|
||||
-------
|
||||
|
||||
* Instead of using the given secret key directly, TweetNaCl.js now copies it to
|
||||
a new array in `nacl.box.keyPair.fromSecretKey` and
|
||||
`nacl.sign.keyPair.fromSecretKey`.
|
||||
|
||||
|
||||
v0.11.2
|
||||
-------
|
||||
|
||||
* Added new constant: `nacl.sign.seedLength`.
|
||||
|
||||
|
||||
v0.11.1
|
||||
-------
|
||||
|
||||
* Even faster hash for both short and long inputs (in `nacl-fast`).
|
||||
|
||||
|
||||
v0.11.0
|
||||
-------
|
||||
|
||||
* Implement `nacl.sign.keyPair.fromSeed` to enable creation of sign key pairs
|
||||
deterministically from a 32-byte seed. (It behaves like
|
||||
[libsodium's](http://doc.libsodium.org/public-key_cryptography/public-key_signatures.html)
|
||||
`crypto_sign_seed_keypair`: the seed becomes a secret part of the secret key.)
|
||||
|
||||
* Fast version now has an improved hash implementation that is 2x-5x faster.
|
||||
|
||||
* Fixed benchmarks, which may have produced incorrect measurements.
|
||||
|
||||
|
||||
v0.10.1
|
||||
-------
|
||||
|
||||
* Exported undocumented `nacl.lowlevel.crypto_core_hsalsa20`.
|
||||
|
||||
|
||||
v0.10.0
|
||||
-------
|
||||
|
||||
* **Signature API breaking change!** `nacl.sign` and `nacl.sign.open` now deal
|
||||
with signed messages, and new `nacl.sign.detached` and
|
||||
`nacl.sign.detached.verify` are available.
|
||||
|
||||
Previously, `nacl.sign` returned a signature, and `nacl.sign.open` accepted a
|
||||
message and "detached" signature. This was unlike NaCl's API, which dealt with
|
||||
signed messages (concatenation of signature and message).
|
||||
|
||||
The new API is:
|
||||
|
||||
nacl.sign(message, secretKey) -> signedMessage
|
||||
nacl.sign.open(signedMessage, publicKey) -> message | null
|
||||
|
||||
Since detached signatures are common, two new API functions were introduced:
|
||||
|
||||
nacl.sign.detached(message, secretKey) -> signature
|
||||
nacl.sign.detached.verify(message, signature, publicKey) -> true | false
|
||||
|
||||
(Note that it's `verify`, not `open`, and it returns a boolean value, unlike
|
||||
`open`, which returns an "unsigned" message.)
|
||||
|
||||
* NPM package now comes without `test` directory to keep it small.
|
||||
|
||||
|
||||
v0.9.2
|
||||
------
|
||||
|
||||
* Improved documentation.
|
||||
* Fast version: increased theoretical message size limit from 2^32-1 to 2^52
|
||||
bytes in Poly1305 (and thus, secretbox and box). However this has no impact
|
||||
in practice since JavaScript arrays or ArrayBuffers are limited to 32-bit
|
||||
indexes, and most implementations won't allocate more than a gigabyte or so.
|
||||
(Obviously, there are no tests for the correctness of implementation.) Also,
|
||||
it's not recommended to use messages that large without splitting them into
|
||||
smaller packets anyway.
|
||||
|
||||
|
||||
v0.9.1
|
||||
------
|
||||
|
||||
* Initial release
|
||||
@ -1,455 +0,0 @@
|
||||
TweetNaCl.js
|
||||
============
|
||||
|
||||
Port of [TweetNaCl](http://tweetnacl.cr.yp.to) / [NaCl](http://nacl.cr.yp.to/)
|
||||
to JavaScript for modern browsers and Node.js. Public domain.
|
||||
|
||||
[
|
||||
](https://travis-ci.org/dchest/tweetnacl-js)
|
||||
|
||||
[Demo](https://dchest.github.io/tweetnacl-js/)
|
||||
|
||||
**:warning: Beta version. The library is stable and API is frozen, however
|
||||
it has not been independently reviewed. If you can help reviewing it, please
|
||||
[contact me](mailto:dmitry@codingrobots.com).**
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Installation](#installation)
|
||||
* [Usage](#usage)
|
||||
* [Public-key authenticated encryption (box)](#public-key-authenticated-encryption-box)
|
||||
* [Secret-key authenticated encryption (secretbox)](#secret-key-authenticated-encryption-secretbox)
|
||||
* [Scalar multiplication](#scalar-multiplication)
|
||||
* [Signatures](#signatures)
|
||||
* [Hashing](#hashing)
|
||||
* [Random bytes generation](#random-bytes-generation)
|
||||
* [Constant-time comparison](#constant-time-comparison)
|
||||
* [Utilities](#utilities)
|
||||
* [Examples](#examples)
|
||||
* [System requirements](#system-requirements)
|
||||
* [Development and testing](#development-and-testing)
|
||||
* [Contributors](#contributors)
|
||||
* [Who uses it](#who-uses-it)
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The primary goal of this project is to produce a translation of TweetNaCl to
|
||||
JavaScript which is as close as possible to the original C implementation, plus
|
||||
a thin layer of idiomatic high-level API on top of it.
|
||||
|
||||
There are two versions, you can use either of them:
|
||||
|
||||
* `nacl.js` is the port of TweetNaCl with minimum differences from the
|
||||
original + high-level API.
|
||||
|
||||
* `nacl-fast.js` is like `nacl.js`, but with some functions replaced with
|
||||
faster versions.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
You can install TweetNaCl.is via a package manager:
|
||||
|
||||
[Bower](http://bower.io):
|
||||
|
||||
$ bower install tweetnacl
|
||||
|
||||
[NPM](https://www.npmjs.org/):
|
||||
|
||||
$ npm install tweetnacl
|
||||
|
||||
or [download source code](https://github.com/dchest/tweetnacl-js/releases).
|
||||
|
||||
|
||||
Usage
|
||||
------
|
||||
|
||||
All API functions accept and return bytes as `Uint8Array`s. If you need to
|
||||
encode or decode strings, use functions from `nacl.util` namespace.
|
||||
|
||||
### Public-key authenticated encryption (box)
|
||||
|
||||
Implements *curve25519-xsalsa20-poly1305*.
|
||||
|
||||
#### nacl.box.keyPair()
|
||||
|
||||
Generates a new random key pair for box and returns it as an object with
|
||||
`publicKey` and `secretKey` members:
|
||||
|
||||
{
|
||||
publicKey: ..., // Uint8Array with 32-byte public key
|
||||
secretKey: ... // Uint8Array with 32-byte secret key
|
||||
}
|
||||
|
||||
|
||||
#### nacl.box.keyPair.fromSecretKey(secretKey)
|
||||
|
||||
Returns a key pair for box with public key corresponding to the given secret
|
||||
key.
|
||||
|
||||
#### nacl.box(message, nonce, theirPublicKey, mySecretKey)
|
||||
|
||||
Encrypt and authenticates message using peer's public key, our secret key, and
|
||||
the given nonce, which must be unique for each distinct message for a key pair.
|
||||
|
||||
Returns an encrypted and authenticated message, which is
|
||||
`nacl.box.overheadLength` longer than the original message.
|
||||
|
||||
#### nacl.box.open(box, nonce, theirPublicKey, mySecretKey)
|
||||
|
||||
Authenticates and decrypts the given box with peer's public key, our secret
|
||||
key, and the given nonce.
|
||||
|
||||
Returns the original message, or `false` if authentication fails.
|
||||
|
||||
#### nacl.box.before(theirPublicKey, mySecretKey)
|
||||
|
||||
Returns a precomputed shared key which can be used in `nacl.box.after` and
|
||||
`nacl.box.open.after`.
|
||||
|
||||
#### nacl.box.after(message, nonce, sharedKey)
|
||||
|
||||
Same as `nacl.box`, but uses a shared key precomputed with `nacl.box.before`.
|
||||
|
||||
#### nacl.box.open.after(box, nonce, sharedKey)
|
||||
|
||||
Same as `nacl.box.open`, but uses a shared key precomputed with `nacl.box.before`.
|
||||
|
||||
#### nacl.box.publicKeyLength = 32
|
||||
|
||||
Length of public key in bytes.
|
||||
|
||||
#### nacl.box.secretKeyLength = 32
|
||||
|
||||
Length of secret key in bytes.
|
||||
|
||||
#### nacl.box.sharedKeyLength = 32
|
||||
|
||||
Length of precomputed shared key in bytes.
|
||||
|
||||
#### nacl.box.nonceLength = 24
|
||||
|
||||
Length of nonce in bytes.
|
||||
|
||||
#### nacl.box.overheadLength = 16
|
||||
|
||||
Length of overhead added to box compared to original message.
|
||||
|
||||
|
||||
### Secret-key authenticated encryption (secretbox)
|
||||
|
||||
Implements *xsalsa20-poly1305*.
|
||||
|
||||
#### nacl.secretbox(message, nonce, key)
|
||||
|
||||
Encrypt and authenticates message using the key and the nonce. The nonce must
|
||||
be unique for each distinct message for this key.
|
||||
|
||||
Returns an encrypted and authenticated message, which is
|
||||
`nacl.secretbox.overheadLength` longer than the original message.
|
||||
|
||||
#### nacl.secretbox.open(box, nonce, key)
|
||||
|
||||
Authenticates and decrypts the given secret box using the key and the nonce.
|
||||
|
||||
Returns the original message, or `false` if authentication fails.
|
||||
|
||||
#### nacl.secretbox.keyLength = 32
|
||||
|
||||
Length of key in bytes.
|
||||
|
||||
#### nacl.secretbox.nonceLength = 24
|
||||
|
||||
Length of nonce in bytes.
|
||||
|
||||
#### nacl.secretbox.overheadLength = 16
|
||||
|
||||
Length of overhead added to secret box compared to original message.
|
||||
|
||||
|
||||
### Scalar multiplication
|
||||
|
||||
Implements *curve25519*.
|
||||
|
||||
#### nacl.scalarMult(n, p)
|
||||
|
||||
Multiplies an integer `n` by a group element `p` and returns the resulting
|
||||
group element.
|
||||
|
||||
#### nacl.scalarMult.base(n)
|
||||
|
||||
Multiplies an integer `n` by a standard group element and returns the resulting
|
||||
group element.
|
||||
|
||||
#### nacl.scalarMult.scalarLength = 32
|
||||
|
||||
Length of scalar in bytes.
|
||||
|
||||
#### nacl.scalarMult.groupElementLength = 32
|
||||
|
||||
Length of group element in bytes.
|
||||
|
||||
|
||||
### Signatures
|
||||
|
||||
Implements [ed25519](http://ed25519.cr.yp.to).
|
||||
|
||||
#### nacl.sign.keyPair()
|
||||
|
||||
Generates new random key pair for signing and returns it as an object with
|
||||
`publicKey` and `secretKey` members:
|
||||
|
||||
{
|
||||
publicKey: ..., // Uint8Array with 32-byte public key
|
||||
secretKey: ... // Uint8Array with 64-byte secret key
|
||||
}
|
||||
|
||||
#### nacl.sign.keyPair.fromSecretKey(secretKey)
|
||||
|
||||
Returns a signing key pair with public key corresponding to the given
|
||||
64-byte secret key. The secret key must have been generated by
|
||||
`nacl.sign.keyPair` or `nacl.sign.keyPair.fromSeed`.
|
||||
|
||||
#### nacl.sign.keyPair.fromSeed(seed)
|
||||
|
||||
Returns a new signing key pair generated deterministically from a 32-byte seed.
|
||||
The seed must contain enough entropy to be secure. This method is not
|
||||
recommended for general use: instead, use `nacl.sign.keyPair` to generate a new
|
||||
key pair from a random seed.
|
||||
|
||||
#### nacl.sign(message, secretKey)
|
||||
|
||||
Signs the message using the secret key and returns a signed message.
|
||||
|
||||
#### nacl.sign.open(signedMessage, publicKey)
|
||||
|
||||
Verifies the signed message and returns the message without signature.
|
||||
|
||||
Returns `null` if verification failed.
|
||||
|
||||
#### nacl.sign.detached(message, secretKey)
|
||||
|
||||
Signs the message using the secret key and returns a signature.
|
||||
|
||||
#### nacl.sign.detached.verify(message, signature, publicKey)
|
||||
|
||||
Verifies the signature for the message and returns `true` if verification
|
||||
succeeded or `false` if it failed.
|
||||
|
||||
#### nacl.sign.publicKeyLength = 32
|
||||
|
||||
Length of signing public key in bytes.
|
||||
|
||||
#### nacl.sign.secretKeyLength = 64
|
||||
|
||||
Length of signing secret key in bytes.
|
||||
|
||||
#### nacl.sign.seedLength = 32
|
||||
|
||||
Length of seed for `nacl.sign.keyPair.fromSeed` in bytes.
|
||||
|
||||
#### nacl.sign.signatureLength = 64
|
||||
|
||||
Length of signature in bytes.
|
||||
|
||||
|
||||
### Hashing
|
||||
|
||||
Implements *SHA-512*.
|
||||
|
||||
#### nacl.hash(message)
|
||||
|
||||
Returns SHA-512 hash of the message.
|
||||
|
||||
#### nacl.hash.hashLength = 64
|
||||
|
||||
Length of hash in bytes.
|
||||
|
||||
|
||||
### Random bytes generation
|
||||
|
||||
#### nacl.randomBytes(length)
|
||||
|
||||
Returns a `Uint8Array` of the given length containing random bytes of
|
||||
cryptographic quality.
|
||||
|
||||
**Implementation note**
|
||||
|
||||
TweetNaCl.js uses the following methods to generate random bytes,
|
||||
depending on the platform it runs on:
|
||||
|
||||
* `window.crypto.getRandomValues` (WebCrypto standard)
|
||||
* `window.msCrypto.getRandomValues` (Internet Explorer 11)
|
||||
* `crypto.randomBytes` (Node.js)
|
||||
|
||||
Note that browsers are required to throw `QuotaExceededError` exception if
|
||||
requested `length` is more than 65536, so do not ask for more than 65536 bytes
|
||||
in *one call* (multiple calls to get as many bytes as you like are okay:
|
||||
browsers can generate infinite amount of random bytes without any bad
|
||||
consequences).
|
||||
|
||||
If the platform doesn't provide a suitable PRNG, the following functions,
|
||||
which require random numbers, will throw exception:
|
||||
|
||||
* `nacl.randomBytes`
|
||||
* `nacl.box.keyPair`
|
||||
* `nacl.sign.keyPair`
|
||||
|
||||
Other functions are deterministic and will continue working.
|
||||
|
||||
If a platform you are targeting doesn't implement secure random number
|
||||
generator, but you somehow have a cryptographically-strong source of entropy
|
||||
(not `Math.random`!), and you know what you are doing, you can plug it into
|
||||
TweetNaCl.js like this:
|
||||
|
||||
nacl.setPRNG(function(x, n) {
|
||||
// ... copy n random bytes into x ...
|
||||
});
|
||||
|
||||
Note that `nacl.setPRNG` *completely replaces* internal random byte generator
|
||||
with the one provided.
|
||||
|
||||
|
||||
### Constant-time comparison
|
||||
|
||||
#### nacl.verify(x, y)
|
||||
|
||||
Compares `x` and `y` in constant time and returns `true` if their lengths are
|
||||
non-zero and equal, and their contents are equal.
|
||||
|
||||
Returns `false` if either of the arguments has zero length, or arguments have
|
||||
different lengths, or their contents differ.
|
||||
|
||||
|
||||
### Utilities
|
||||
|
||||
Encoding/decoding functions are provided for convenience. They are correct,
|
||||
however their performance and wide compatibility with uncommon runtimes is not
|
||||
something that is considered important compared to the simplicity and size of
|
||||
implementation. You can use third-party libraries if you need to.
|
||||
|
||||
#### nacl.util.decodeUTF8(string)
|
||||
|
||||
Decodes string and returns `Uint8Array` of bytes.
|
||||
|
||||
#### nacl.util.encodeUTF8(array)
|
||||
|
||||
Encodes `Uint8Array` or `Array` of bytes into string.
|
||||
|
||||
#### nacl.util.decodeBase64(string)
|
||||
|
||||
Decodes Base-64 encoded string and returns `Uint8Array` of bytes.
|
||||
|
||||
#### nacl.util.encodeBase64(array)
|
||||
|
||||
Encodes `Uint8Array` or `Array` of bytes into string using Base-64 encoding.
|
||||
|
||||
|
||||
System requirements
|
||||
-------------------
|
||||
|
||||
TweetNaCl.js supports modern browsers that have a cryptographically secure
|
||||
pseudorandom number generator and typed arrays, including the latest versions
|
||||
of:
|
||||
|
||||
* Chrome
|
||||
* Firefox
|
||||
* Safari (Mac, iOS)
|
||||
* Internet Explorer 11
|
||||
|
||||
Other systems:
|
||||
|
||||
* Node.js (we test on 0.10 and later)
|
||||
|
||||
|
||||
Development and testing
|
||||
------------------------
|
||||
|
||||
Install NPM modules needed for development:
|
||||
|
||||
$ npm install
|
||||
|
||||
To build minified versions:
|
||||
|
||||
$ npm run build
|
||||
|
||||
Tests use minified version, so make sure to rebuild it every time you change
|
||||
`nacl.js` or `nacl-fast.js`.
|
||||
|
||||
### Testing
|
||||
|
||||
To run tests in Node.js:
|
||||
|
||||
$ npm test
|
||||
|
||||
By default all tests described here work on `nacl.min.js`. To test other
|
||||
versions, set environment variable `NACL_SRC` to the file name you want to test.
|
||||
For example, the following command will test fast minified version:
|
||||
|
||||
$ NACL_SRC=nacl-fast.min.js npm test
|
||||
|
||||
To run full suite of tests in Node.hs, including comparing outputs of
|
||||
JavaScript port to outputs of the original C version:
|
||||
|
||||
$ npm run testall
|
||||
|
||||
To prepare tests for browsers:
|
||||
|
||||
$ npm run browser
|
||||
|
||||
and then open `tests/browser/test.html` (or `tests/browser/test-fast.html`) to
|
||||
run them.
|
||||
|
||||
To run headless browser tests with `testling`:
|
||||
|
||||
$ npm run testling
|
||||
|
||||
(If you get `Error: spawn ENOENT`, install *xvfb*: `sudo apt-get install xvfb`.)
|
||||
|
||||
### Benchmarking
|
||||
|
||||
To run benchmarks in Node.js:
|
||||
|
||||
$ npm run bench
|
||||
$ NACL_SRC=nacl-fast.min.js npm run bench
|
||||
|
||||
To run benchmarks in a browser, open `test/benchmark/bench.html` (or
|
||||
`test/benchmark/bench-fast.html`).
|
||||
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
JavaScript port:
|
||||
|
||||
* [Dmitry Chestnykh](http://github.com/dchest) (ported xsalsa20, poly1305, curve25519)
|
||||
* [Devi Mandiri](https://github.com/devi) (ported curve25519, ed25519, sha512)
|
||||
|
||||
Original authors of [NaCl](http://nacl.cr.yp.to), [TweetNaCl](http://tweetnacl.cr.yp.to)
|
||||
and [Poly1305-donna](https://github.com/floodyberry/poly1305-donna)
|
||||
(who are *not* responsible for any errors in this implementation):
|
||||
|
||||
* [Daniel J. Bernstein](http://cr.yp.to/djb.html)
|
||||
* Wesley Janssen
|
||||
* [Tanja Lange](http://hyperelliptic.org/tanja)
|
||||
* [Peter Schwabe](http://www.cryptojedi.org/users/peter/)
|
||||
* [Matthew Dempsky](https://github.com/mdempsky)
|
||||
* [Andrew Moon](https://github.com/floodyberry)
|
||||
|
||||
Contributors have dedicated their work to the public domain.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
|
||||
|
||||
Who uses it
|
||||
-----------
|
||||
|
||||
Some notable users of TweetNaCl.js:
|
||||
|
||||
* [miniLock](http://minilock.io/)
|
||||
* [Stellar](https://www.stellar.org/)
|
||||
@ -1,36 +0,0 @@
|
||||
{
|
||||
"name": "tweetnacl",
|
||||
"version": "0.12.2",
|
||||
"homepage": "https://dchest.github.io/tweetnacl-js",
|
||||
"authors": [
|
||||
"TweetNaCl.js Contributors"
|
||||
],
|
||||
"description": "Port of TweetNaCl cryptographic library to JavaScript",
|
||||
"main": "nacl.js",
|
||||
"moduleType": [
|
||||
"globals",
|
||||
"node"
|
||||
],
|
||||
"keywords": [
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"encrypt",
|
||||
"hash",
|
||||
"key",
|
||||
"nacl",
|
||||
"poly1305",
|
||||
"public",
|
||||
"salsa20",
|
||||
"signatures"
|
||||
],
|
||||
"license": "Public domain",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
2
src/tweetnacl/nacl-fast.min.js
vendored
2
src/tweetnacl/nacl-fast.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
1
src/tweetnacl/nacl.min.js
vendored
1
src/tweetnacl/nacl.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,57 +0,0 @@
|
||||
{
|
||||
"name": "tweetnacl",
|
||||
"version": "0.12.2",
|
||||
"description": "Port of TweetNaCl cryptographic library to JavaScript",
|
||||
"main": "nacl.js",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "uglifyjs nacl.js -c -m -o nacl.min.js && uglifyjs nacl-fast.js -c -m -o nacl-fast.min.js",
|
||||
"test": "tape test/*.js | faucet",
|
||||
"testall": "make -C test/c && tape test/*.js test/c/*.js | faucet",
|
||||
"browser": "browserify test/browser/init.js test/*.js | uglifyjs -c -m -o test/browser/_bundle.js 2>/dev/null",
|
||||
"browser-quick": "browserify test/browser/init.js test/*.quick.js | uglifyjs -c -m -o test/browser/_bundle-quick.js 2>/dev/null",
|
||||
"testling": "browserify test/browser/testling_init.js test/*.js | testling | faucet",
|
||||
"firefox": "browserify test/browser/testling_init.js test/*.js | testling -x firefox | faucet",
|
||||
"chrome": "browserify test/browser/testling_init.js test/*.js | testling -x google-chrome | faucet",
|
||||
"bench": "node test/benchmark/bench.js"
|
||||
},
|
||||
"testling": {
|
||||
"files": "test/*.js",
|
||||
"browsers": [
|
||||
"ie/11..latest",
|
||||
"chrome/22..latest",
|
||||
"firefox/16..latest",
|
||||
"safari/latest",
|
||||
"opera/11.0..latest",
|
||||
"iphone/6..latest",
|
||||
"ipad/6..latest",
|
||||
"android-browser/latest"
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dchest/tweetnacl-js.git"
|
||||
},
|
||||
"keywords": [
|
||||
"crypto",
|
||||
"cryptography",
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"encrypt",
|
||||
"hash",
|
||||
"key",
|
||||
"nacl",
|
||||
"poly1305",
|
||||
"public",
|
||||
"salsa20",
|
||||
"signatures"
|
||||
],
|
||||
"author": "TweetNaCl-js contributors",
|
||||
"license": "Public domain",
|
||||
"bugs": {
|
||||
"url": "https://github.com/dchest/tweetnacl-js/issues"
|
||||
},
|
||||
"homepage": "https://dchest.github.io/tweetnacl-js"
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var b64Vectors = require('./data/base64.random');
|
||||
|
||||
test('nacl.util.encodeBase64 random test vectors', function(t) {
|
||||
b64Vectors.forEach(function(vec) {
|
||||
var b = new Uint8Array(vec[0]);
|
||||
var s = vec[1];
|
||||
t.equal(nacl.util.encodeBase64(b), s);
|
||||
t.deepEqual(nacl.util.decodeBase64(s), b);
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var testBytes = new Uint8Array([208,159,209,128,208,184,208,178,208,181,209,130,44,32,78,97,67,108]);
|
||||
var utf8String = "Привет, NaCl";
|
||||
var b64String = "0J/RgNC40LLQtdGCLCBOYUNs";
|
||||
|
||||
test('nacl.util.decodeUTF8', function(t) {
|
||||
t.plan(1);
|
||||
t.deepEqual(nacl.util.decodeUTF8(utf8String), testBytes);
|
||||
});
|
||||
|
||||
test('nacl.util.encodeUTF8', function(t) {
|
||||
t.plan(1);
|
||||
t.equal(nacl.util.encodeUTF8(testBytes), utf8String);
|
||||
});
|
||||
|
||||
test('nacl.util.decodeBase64', function(t) {
|
||||
t.plan(1);
|
||||
t.deepEqual(nacl.util.decodeBase64(b64String), testBytes);
|
||||
});
|
||||
|
||||
test('nacl.util.encodeBase64', function(t) {
|
||||
t.plan(1);
|
||||
t.equal(nacl.util.encodeBase64(testBytes), b64String);
|
||||
});
|
||||
@ -1,16 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
test('nacl.verify', function(t) {
|
||||
t.ok(nacl.verify(new Uint8Array(1), new Uint8Array(1)), 'equal arrays of length 1 should verify');
|
||||
t.ok(nacl.verify(new Uint8Array(1000), new Uint8Array(1000)), 'equal arrays of length 1000 should verify');
|
||||
var a = new Uint8Array(764), b = new Uint8Array(764);
|
||||
for (i = 0; i < a.length; i++) a[i] = b[i] = i & 0xff;
|
||||
t.ok(nacl.verify(a, b), 'equal arrays should verify');
|
||||
t.ok(nacl.verify(a, a), 'same arrays should verify');
|
||||
b[0] = 255;
|
||||
t.notOk(nacl.verify(a, b), 'different arrays don\'t verify');
|
||||
t.notOk(nacl.verify(new Uint8Array(1), new Uint8Array(10)), 'arrays of different lengths should not verify');
|
||||
t.notOk(nacl.verify(new Uint8Array(0), new Uint8Array(0)), 'zero-length arrays should not verify');
|
||||
t.end();
|
||||
});
|
||||
@ -1,16 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
test('nacl.randomBytes', function(t) {
|
||||
t.plan(1);
|
||||
var set = {}, s, i;
|
||||
for (i = 0; i < 10000; i++) {
|
||||
s = nacl.util.encodeBase64(nacl.randomBytes(32));
|
||||
if (set[s]) {
|
||||
t.fail("duplicate random sequence! ", s);
|
||||
return;
|
||||
}
|
||||
set[s] = true;
|
||||
}
|
||||
t.pass('no collisions');
|
||||
});
|
||||
@ -1,17 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var specVectors = require('./data/onetimeauth.spec');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.lowlevel.crypto_onetimeauth specified vectors', function(t) {
|
||||
var out = new Uint8Array(16);
|
||||
specVectors.forEach(function(v) {
|
||||
nacl.lowlevel.crypto_onetimeauth(out, 0, v.m, 0, v.m.length, v.k);
|
||||
t.equal(enc(out), enc(v.out));
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var randomVectors = require('./data/secretbox.random');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.secretbox random test vectors', function(t) {
|
||||
randomVectors.forEach(function(vec) {
|
||||
var key = dec(vec[0]);
|
||||
var nonce = dec(vec[1]);
|
||||
var msg = dec(vec[2]);
|
||||
var goodBox = dec(vec[3]);
|
||||
var box = nacl.secretbox(msg, nonce, key);
|
||||
t.ok(box, 'box should be created');
|
||||
t.equal(enc(box), enc(goodBox));
|
||||
var openedBox = nacl.secretbox.open(goodBox, nonce, key);
|
||||
t.ok(openedBox, 'box should open');
|
||||
t.equal(enc(openedBox), enc(msg));
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.secretbox and nacl.secretbox.open', function(t) {
|
||||
var key = new Uint8Array(nacl.secretbox.keyLength);
|
||||
var nonce = new Uint8Array(nacl.secretbox.nonceLength);
|
||||
for (var i = 0; i < key.length; i++) key[i] = i & 0xff;
|
||||
for (i = 0; i < nonce.length; i++) nonce[i] = (32+i) & 0xff;
|
||||
var msg = nacl.util.decodeUTF8('message to encrypt');
|
||||
var box = nacl.secretbox(msg, nonce, key);
|
||||
var openedMsg = nacl.secretbox.open(box, nonce, key);
|
||||
t.equal(nacl.util.encodeUTF8(openedMsg), nacl.util.encodeUTF8(msg), 'opened messages should be equal');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.secretbox.open with invalid box', function(t) {
|
||||
var key = new Uint8Array(nacl.secretbox.keyLength);
|
||||
var nonce = new Uint8Array(nacl.secretbox.nonceLength);
|
||||
t.equal(nacl.secretbox.open(new Uint8Array(0), nonce, key), false);
|
||||
t.equal(nacl.secretbox.open(new Uint8Array(10), nonce, key), false);
|
||||
t.equal(nacl.secretbox.open(new Uint8Array(100), nonce, key), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.secretbox.open with invalid nonce', function(t) {
|
||||
var key = new Uint8Array(nacl.secretbox.keyLength);
|
||||
var nonce = new Uint8Array(nacl.secretbox.nonceLength);
|
||||
for (i = 0; i < nonce.length; i++) nonce[i] = i & 0xff;
|
||||
var msg = nacl.util.decodeUTF8('message to encrypt');
|
||||
var box = nacl.secretbox(msg, nonce, key);
|
||||
t.equal(nacl.util.encodeUTF8(nacl.secretbox.open(box, nonce, key)),
|
||||
nacl.util.encodeUTF8(msg));
|
||||
nonce[0] = 255;
|
||||
t.equal(nacl.secretbox.open(box, nonce, key), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.secretbox.open with invalid key', function(t) {
|
||||
var key = new Uint8Array(nacl.secretbox.keyLength);
|
||||
for (var i = 0; i < key.length; i++) key[i] = i & 0xff;
|
||||
var nonce = new Uint8Array(nacl.secretbox.nonceLength);
|
||||
var msg = nacl.util.decodeUTF8('message to encrypt');
|
||||
var box = nacl.secretbox(msg, nonce, key);
|
||||
t.equal(nacl.util.encodeUTF8(nacl.secretbox.open(box, nonce, key)),
|
||||
nacl.util.encodeUTF8(msg));
|
||||
key[0] = 255;
|
||||
t.equal(nacl.secretbox.open(box, nonce, key), false);
|
||||
t.end();
|
||||
});
|
||||
@ -1,43 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var randomVectors = require('./data/scalarmult.random');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.scalarMult.base', function(t) {
|
||||
// This takes takes a bit of time.
|
||||
// Similar to https://code.google.com/p/go/source/browse/curve25519/curve25519_test.go?repo=crypto
|
||||
var golden = new Uint8Array([0x89, 0x16, 0x1f, 0xde, 0x88, 0x7b, 0x2b, 0x53, 0xde, 0x54,
|
||||
0x9a, 0xf4, 0x83, 0x94, 0x01, 0x06, 0xec, 0xc1, 0x14, 0xd6, 0x98, 0x2d,
|
||||
0xaa, 0x98, 0x25, 0x6d, 0xe2, 0x3b, 0xdf, 0x77, 0x66, 0x1a]);
|
||||
var input = new Uint8Array([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
for (var i = 0; i < 200; i++) {
|
||||
input = nacl.scalarMult.base(input);
|
||||
}
|
||||
t.equal(enc(input), enc(golden));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.scalarMult and nacl.scalarMult.base random test vectors', function(t) {
|
||||
randomVectors.forEach(function(vec) {
|
||||
var pk1 = dec(vec[0]);
|
||||
var sk1 = dec(vec[1]);
|
||||
var pk2 = dec(vec[2]);
|
||||
var sk2 = dec(vec[3]);
|
||||
var out = dec(vec[4]);
|
||||
|
||||
var jpk1 = nacl.scalarMult.base(sk1);
|
||||
t.equal(enc(jpk1), enc(pk1));
|
||||
var jpk2 = nacl.scalarMult.base(sk2);
|
||||
t.equal(enc(jpk2), enc(pk2));
|
||||
var jout1 = nacl.scalarMult(sk1, pk2);
|
||||
t.equal(enc(jout1), enc(out));
|
||||
var jout2 = nacl.scalarMult(sk2, pk1);
|
||||
t.equal(enc(jout2), enc(out));
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var randomVectors = require('./data/box.random');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.box random test vectors', function(t) {
|
||||
var nonce = new Uint8Array(nacl.box.nonceLength);
|
||||
randomVectors.forEach(function(vec) {
|
||||
var pk1 = dec(vec[0]);
|
||||
var sk2 = dec(vec[1]);
|
||||
var msg = dec(vec[2]);
|
||||
var goodBox = dec(vec[3]);
|
||||
var box = nacl.box(msg, nonce, pk1, sk2);
|
||||
t.equal(enc(box), enc(goodBox));
|
||||
var openedBox = nacl.box.open(goodBox, nonce, pk1, sk2);
|
||||
t.equal(enc(openedBox), enc(msg));
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
@ -1,78 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.box.keyPair', function(t) {
|
||||
var keys = nacl.box.keyPair();
|
||||
t.ok(keys.secretKey && keys.secretKey.length === nacl.box.secretKeyLength, 'has secret key');
|
||||
t.ok(keys.publicKey && keys.publicKey.length === nacl.box.publicKeyLength, 'has public key');
|
||||
t.notEqual(enc(keys.secretKey), enc(keys.publicKey));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.box.keyPair.fromSecretKey', function(t) {
|
||||
var k1 = nacl.box.keyPair();
|
||||
var k2 = nacl.box.keyPair.fromSecretKey(k1.secretKey);
|
||||
t.equal(enc(k2.secretKey), enc(k1.secretKey));
|
||||
t.equal(enc(k2.publicKey), enc(k1.publicKey));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.box and nacl.box.open', function(t) {
|
||||
var clientKeys = nacl.box.keyPair();
|
||||
var serverKeys = nacl.box.keyPair();
|
||||
var nonce = new Uint8Array(nacl.box.nonceLength);
|
||||
for (i = 0; i < nonce.length; i++) nonce[i] = (32+i) & 0xff;
|
||||
var msg = nacl.util.decodeUTF8('message to encrypt');
|
||||
var clientBox = nacl.box(msg, nonce, serverKeys.publicKey, clientKeys.secretKey);
|
||||
var clientMsg = nacl.box.open(clientBox, nonce, clientKeys.publicKey, serverKeys.secretKey);
|
||||
t.equal(nacl.util.encodeUTF8(clientMsg), nacl.util.encodeUTF8(msg));
|
||||
var serverBox = nacl.box(msg, nonce, clientKeys.publicKey, serverKeys.secretKey);
|
||||
t.equal(enc(clientBox), enc(serverBox));
|
||||
var serverMsg = nacl.box.open(serverBox, nonce, serverKeys.publicKey, clientKeys.secretKey);
|
||||
t.equal(nacl.util.encodeUTF8(serverMsg), nacl.util.encodeUTF8(msg));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.box.open with invalid box', function(t) {
|
||||
var clientKeys = nacl.box.keyPair();
|
||||
var serverKeys = nacl.box.keyPair();
|
||||
var nonce = new Uint8Array(nacl.box.nonceLength);
|
||||
t.equal(nacl.box.open(new Uint8Array(0), nonce, serverKeys.publicKey, clientKeys.secretKey), false);
|
||||
t.equal(nacl.box.open(new Uint8Array(10), nonce, serverKeys.publicKey, clientKeys.secretKey), false);
|
||||
t.equal(nacl.box.open(new Uint8Array(100), nonce, serverKeys.publicKey, clientKeys.secretKey), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.box.open with invalid nonce', function(t) {
|
||||
var clientKeys = nacl.box.keyPair();
|
||||
var serverKeys = nacl.box.keyPair();
|
||||
var nonce = new Uint8Array(nacl.box.nonceLength);
|
||||
for (i = 0; i < nonce.length; i++) nonce[i] = i & 0xff;
|
||||
var msg = nacl.util.decodeUTF8('message to encrypt');
|
||||
var box = nacl.box(msg, nonce, clientKeys.publicKey, serverKeys.secretKey);
|
||||
t.equal(nacl.util.encodeUTF8(nacl.box.open(box, nonce, serverKeys.publicKey, clientKeys.secretKey)),
|
||||
nacl.util.encodeUTF8(msg));
|
||||
nonce[0] = 255;
|
||||
t.equal(nacl.box.open(box, nonce, serverKeys.publicKey, clientKeys.secretKey), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.box.open with invalid keys', function(t) {
|
||||
var clientKeys = nacl.box.keyPair();
|
||||
var serverKeys = nacl.box.keyPair();
|
||||
var nonce = new Uint8Array(nacl.box.nonceLength);
|
||||
var msg = nacl.util.decodeUTF8('message to encrypt');
|
||||
var box = nacl.box(msg, nonce, clientKeys.publicKey, serverKeys.secretKey);
|
||||
t.equal(nacl.util.encodeUTF8(nacl.box.open(box, nonce, serverKeys.publicKey, clientKeys.secretKey)),
|
||||
nacl.util.encodeUTF8(msg));
|
||||
t.equal(nacl.util.encodeUTF8(nacl.box.open(box, nonce, clientKeys.publicKey, serverKeys.secretKey)),
|
||||
nacl.util.encodeUTF8(msg));
|
||||
badPublicKey = new Uint8Array(nacl.box.publicKeyLength);
|
||||
t.equal(nacl.box.open(box, nonce, badPublicKey, clientKeys.secretKey), false);
|
||||
badSecretKey = new Uint8Array(nacl.box.secretKeyLength);
|
||||
t.equal(nacl.box.open(box, nonce, serverKeys.publicKey, badSecretKey), false);
|
||||
t.end();
|
||||
});
|
||||
@ -1,17 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var randomVectors = require('./data/hash.random');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.hash random test vectors', function(t) {
|
||||
randomVectors.forEach(function(vec) {
|
||||
var msg = dec(vec[0]);
|
||||
var goodHash = dec(vec[1]);
|
||||
var hash = nacl.hash(msg);
|
||||
t.equal(enc(hash), enc(goodHash));
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
@ -1,29 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var specVectors = require('./data/hash.spec');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.hash length', function(t) {
|
||||
t.equal(nacl.hash(new Uint8Array(0)).length, 64);
|
||||
t.equal(nacl.hash(new Uint8Array(100)).length, 64);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.hash exceptions for bad types', function(t) {
|
||||
t.throws(function() { nacl.hash('string'); }, TypeError, 'should throw TypeError for string type');
|
||||
t.throws(function() { nacl.hash([1,2,3]); }, TypeError, 'should throw TypeError for array type');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.hash specified test vectors', function(t) {
|
||||
specVectors.forEach(function(vec) {
|
||||
var goodHash = new Uint8Array(vec[0]);
|
||||
var msg = new Uint8Array(vec[1]);
|
||||
var hash = nacl.hash(msg);
|
||||
t.equal(enc(hash), enc(goodHash));
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
@ -1,38 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var specVectors = require('./data/sign.spec');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.sign and nacl.sign.open specified vectors', function(t) {
|
||||
specVectors.forEach(function(vec) {
|
||||
var keys = nacl.sign.keyPair.fromSecretKey(dec(vec[0]));
|
||||
var msg = dec(vec[1]);
|
||||
var goodSig = dec(vec[2]);
|
||||
|
||||
var signedMsg = nacl.sign(msg, keys.secretKey);
|
||||
t.equal(enc(signedMsg.subarray(0, nacl.sign.signatureLength)), enc(goodSig), 'signatures must be equal');
|
||||
var openedMsg = nacl.sign.open(signedMsg, keys.publicKey);
|
||||
t.equal(enc(openedMsg), enc(msg), 'messages must be equal');
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.sign.detached and nacl.sign.detached.verify some specified vectors', function(t) {
|
||||
specVectors.forEach(function(vec, i) {
|
||||
// We don't need to test all, as internals are already tested above.
|
||||
if (i % 100 !== 0) return;
|
||||
|
||||
var keys = nacl.sign.keyPair.fromSecretKey(dec(vec[0]));
|
||||
var msg = dec(vec[1]);
|
||||
var goodSig = dec(vec[2]);
|
||||
|
||||
var sig = nacl.sign.detached(msg, keys.secretKey);
|
||||
t.equal(enc(sig), enc(goodSig), 'signatures must be equal');
|
||||
var result = nacl.sign.detached.verify(msg, sig, keys.publicKey);
|
||||
t.ok(result, 'signature must be verified');
|
||||
});
|
||||
t.end();
|
||||
});
|
||||
@ -1,80 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var test = require('tape');
|
||||
|
||||
var enc = nacl.util.encodeBase64,
|
||||
dec = nacl.util.decodeBase64;
|
||||
|
||||
test('nacl.sign.keyPair', function(t) {
|
||||
var keys = nacl.sign.keyPair();
|
||||
t.ok(keys.secretKey && keys.secretKey.length === nacl.sign.secretKeyLength, 'has secret key');
|
||||
t.ok(keys.publicKey && keys.publicKey.length === nacl.sign.publicKeyLength, 'has public key');
|
||||
t.notEqual(enc(keys.secretKey), enc(keys.publicKey));
|
||||
var newKeys = nacl.sign.keyPair();
|
||||
t.notEqual(enc(newKeys.secretKey), enc(keys.secretKey), 'two keys differ');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.sign.keyPair.fromSecretKey', function(t) {
|
||||
var k1 = nacl.sign.keyPair();
|
||||
var k2 = nacl.sign.keyPair.fromSecretKey(k1.secretKey);
|
||||
t.equal(enc(k2.secretKey), enc(k1.secretKey));
|
||||
t.equal(enc(k2.publicKey), enc(k1.publicKey));
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.sign.keyPair.fromSeed', function(t) {
|
||||
var seed = nacl.randomBytes(nacl.sign.seedLength);
|
||||
var k1 = nacl.sign.keyPair.fromSeed(seed);
|
||||
var k2 = nacl.sign.keyPair.fromSeed(seed);
|
||||
t.equal(k1.secretKey.length, nacl.sign.secretKeyLength);
|
||||
t.equal(k1.publicKey.length, nacl.sign.publicKeyLength);
|
||||
t.equal(k2.secretKey.length, nacl.sign.secretKeyLength);
|
||||
t.equal(k2.publicKey.length, nacl.sign.publicKeyLength);
|
||||
t.equal(enc(k2.secretKey), enc(k1.secretKey));
|
||||
t.equal(enc(k2.publicKey), enc(k1.publicKey));
|
||||
var seed2 = nacl.randomBytes(nacl.sign.seedLength);
|
||||
var k3 = nacl.sign.keyPair.fromSeed(seed2);
|
||||
t.equal(k3.secretKey.length, nacl.sign.secretKeyLength);
|
||||
t.equal(k3.publicKey.length, nacl.sign.publicKeyLength);
|
||||
t.notEqual(enc(k3.secretKey), enc(k1.secretKey));
|
||||
t.notEqual(enc(k3.publicKey), enc(k1.publicKey));
|
||||
t.throws(function() { nacl.sign.keyPair.fromSeed(seed2.subarray(0, 16)) }, Error, 'should throw error for wrong seed size');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.sign and nacl.sign.open', function(t) {
|
||||
var k = nacl.sign.keyPair();
|
||||
var m = new Uint8Array(100);
|
||||
for (var i = 0; i < m.length; i++) m[i] = i & 0xff;
|
||||
var sm = nacl.sign(m, k.secretKey);
|
||||
t.ok(sm.length > m.length, 'signed message length should be greater than message length');
|
||||
var om = nacl.sign.open(sm, k.publicKey);
|
||||
t.deepEqual(om, m);
|
||||
t.throws(function() { nacl.sign.open(sm, k.publicKey.subarray(1)) }, Error, 'throws error for wrong public key size');
|
||||
var badPublicKey = new Uint8Array(k.publicKey.length);
|
||||
om = nacl.sign.open(sm, badPublicKey);
|
||||
t.equal(om, null, 'opened message must be null when using wrong public key');
|
||||
for (i = 80; i < 90; i++) sm[i] = 0;
|
||||
om = nacl.sign.open(sm, k.publicKey);
|
||||
t.equal(om, null, 'opened message must be null when opening bad signed message');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('nacl.sign.detached and nacl.sign.detached.verify', function(t) {
|
||||
var k = nacl.sign.keyPair();
|
||||
var m = new Uint8Array(100);
|
||||
for (var i = 0; i < m.length; i++) m[i] = i & 0xff;
|
||||
var sig = nacl.sign.detached(m, k.secretKey);
|
||||
t.ok(sig.length === nacl.sign.signatureLength, 'signature must have correct length');
|
||||
var result = nacl.sign.detached.verify(m, sig, k.publicKey);
|
||||
t.ok(result, 'signature must be verified');
|
||||
t.throws(function() { nacl.sign.detached.verify(m, sig, k.publicKey.subarray(1)) }, Error, 'throws error for wrong public key size');
|
||||
t.throws(function() { nacl.sign.detached.verify(m, sig.subarray(1), k.publicKey) }, Error, 'throws error for wrong signature size');
|
||||
var badPublicKey = new Uint8Array(k.publicKey.length);
|
||||
result = nacl.sign.detached.verify(m, sig, badPublicKey);
|
||||
t.equal(result, false, 'signature must not be verified with wrong public key');
|
||||
for (i = 0; i < 10; i++) sig[i] = 0;
|
||||
result = nacl.sign.detached.verify(m, sig, k.publicKey);
|
||||
t.equal(result, false, 'bad signature must not be verified');
|
||||
t.end();
|
||||
});
|
||||
@ -1,11 +0,0 @@
|
||||
This directory contains benchmarks that run in Node.js and browsers.
|
||||
|
||||
To run benchmarks in Node.js, from the root project directory:
|
||||
|
||||
$ npm run bench
|
||||
|
||||
alternatively, in this directory, run:
|
||||
|
||||
$ node bench.js
|
||||
|
||||
To run benchmarks in a browser, open bench.html.
|
||||
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>TweetNaCl-js Benchmarks (fast)</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TweetNaCl-js Benchmarks (fast)</h1>
|
||||
<script src="../../nacl-fast.min.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<script src="bench.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,13 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>TweetNaCl-js Benchmarks</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TweetNaCl-js Benchmarks</h1>
|
||||
<script src="../../nacl.min.js"></script>
|
||||
<script src="helpers.js"></script>
|
||||
<script src="bench.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,164 +0,0 @@
|
||||
var nacl = (typeof window !== 'undefined') ? window.nacl : require('../../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var helpers = (typeof require !== 'undefined') ? require('./helpers') : window.helpers;
|
||||
var log = helpers.log;
|
||||
|
||||
if (!nacl) throw new Error('nacl not loaded');
|
||||
|
||||
function benchmark(fn, bytes, num) {
|
||||
if (!num) num = 1000;
|
||||
var i, elapsed, start = new Date();
|
||||
while (1) {
|
||||
for (i = 0; i < num; i++) fn();
|
||||
elapsed = (new Date()) - start;
|
||||
if (elapsed < 500) {
|
||||
num += num*1000/elapsed/2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log.print(' ' + ((bytes*num/1024/1024*1000)/elapsed).toFixed(3), 'MB/s');
|
||||
log.print(' ' + ((num*1000)/elapsed).toFixed(3), 'ops/s');
|
||||
}
|
||||
|
||||
function benchmarkOps(fn, num) {
|
||||
var i, elapsed, start = new Date();
|
||||
while (1) {
|
||||
for (i = 0; i < num; i++) {
|
||||
fn();
|
||||
}
|
||||
elapsed = (new Date()) - start;
|
||||
if (elapsed < 500) {
|
||||
num += num*1000/elapsed/2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
log.print(' ' + ((num*1000)/elapsed).toFixed(3), 'ops/s');
|
||||
}
|
||||
|
||||
function crypto_stream_xor_benchmark() {
|
||||
log.start('Benchmarking crypto_stream_xor');
|
||||
var m = new Uint8Array(1024),
|
||||
n = new Uint8Array(24),
|
||||
k = new Uint8Array(32),
|
||||
out = new Uint8Array(1024);
|
||||
for (i = 0; i < 1024; i++) m[i] = i & 255;
|
||||
for (i = 0; i < 24; i++) n[i] = i;
|
||||
for (i = 0; i < 32; i++) k[i] = i;
|
||||
benchmark(function(){
|
||||
nacl.lowlevel.crypto_stream_xor(out, 0, m, 0, m.length, n, k);
|
||||
}, m.length);
|
||||
}
|
||||
|
||||
function crypto_onetimeauth_benchmark() {
|
||||
log.start('Benchmarking crypto_onetimeauth');
|
||||
var m = new Uint8Array(1024),
|
||||
out = new Uint8Array(1024),
|
||||
k = new Uint8Array([0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1]);
|
||||
for (i = 0; i < 1024; i++) {
|
||||
m[i] = i & 255;
|
||||
}
|
||||
benchmark(function(){
|
||||
nacl.lowlevel.crypto_onetimeauth(out, 0, m, 0, m.length, k);
|
||||
}, m.length);
|
||||
}
|
||||
|
||||
function crypto_secretbox_benchmark() {
|
||||
log.start('Benchmarking crypto_secretbox');
|
||||
var i, k = new Uint8Array(32), n = new Uint8Array(24),
|
||||
m = new Uint8Array(1024), c = new Uint8Array(1024);
|
||||
for (i = 0; i < 32; i++) k[i] = 1;
|
||||
for (i = 0; i < 24; i++) n[i] = 2;
|
||||
for (i = 0; i < 1024; i++) m[i] = 3;
|
||||
benchmark(function() {
|
||||
nacl.lowlevel.crypto_secretbox(c, m, m.length, n, k);
|
||||
}, m.length);
|
||||
}
|
||||
|
||||
function secretbox_seal_open_benchmark() {
|
||||
var key = new Uint8Array(32),
|
||||
nonce = new Uint8Array(24),
|
||||
msg = new Uint8Array(1024),
|
||||
box, i;
|
||||
for (i = 0; i < 32; i++) key[i] = 1;
|
||||
for (i = 0; i < 24; i++) nonce[i] = 2;
|
||||
for (i = 0; i < 1024; i++) msg[i] = 3;
|
||||
|
||||
log.start('Benchmarking secretbox');
|
||||
benchmark(function() {
|
||||
box = nacl.secretbox(msg, nonce, key);
|
||||
}, msg.length);
|
||||
log.start('Benchmarking secretbox.open');
|
||||
benchmark(function() {
|
||||
nacl.secretbox.open(box, nonce, key);
|
||||
}, msg.length);
|
||||
}
|
||||
|
||||
function crypto_scalarmult_base_benchmark() {
|
||||
log.start('Benchmarking crypto_scalarmult_base');
|
||||
var n = new Uint8Array(32), q = new Uint8Array(32);
|
||||
for (var i = 0; i < 32; i++) n[i] = i;
|
||||
benchmarkOps(function() {
|
||||
nacl.lowlevel.crypto_scalarmult_base(q, n);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function box_seal_open_benchmark() {
|
||||
var pk1 = new Uint8Array(32), sk1 = new Uint8Array(32),
|
||||
pk2 = new Uint8Array(32), sk2 = new Uint8Array(32);
|
||||
nacl.lowlevel.crypto_box_keypair(pk1, sk1);
|
||||
nacl.lowlevel.crypto_box_keypair(pk2, sk2);
|
||||
var nonce = nacl.util.decodeUTF8('123456789012345678901234');
|
||||
var msg = nacl.util.decodeUTF8((new Array(1024)).join('a'));
|
||||
var box = null;
|
||||
log.start('Benchmarking box');
|
||||
benchmark(function() {
|
||||
box = nacl.box(msg, nonce, pk1, sk2);
|
||||
}, msg.length, 20);
|
||||
log.start('Benchmarking box.open');
|
||||
benchmark(function() {
|
||||
nacl.box.open(box, nonce, pk2, sk1);
|
||||
}, msg.length, 20);
|
||||
}
|
||||
|
||||
function sign_open_benchmark() {
|
||||
var k = nacl.sign.keyPair();
|
||||
var sk = k.secretKey;
|
||||
var pk = k.publicKey;
|
||||
var msg = nacl.util.decodeUTF8((new Array(128)).join('a'));
|
||||
var sm;
|
||||
log.start('Benchmarking sign');
|
||||
benchmark(function() {
|
||||
sm = nacl.sign(msg, sk);
|
||||
}, msg.length, 20);
|
||||
log.start('Benchmarking sign.open');
|
||||
benchmark(function() {
|
||||
nacl.sign.open(sm, pk);
|
||||
}, msg.length, 20);
|
||||
}
|
||||
|
||||
function crypto_hash_benchmark() {
|
||||
log.start('Benchmarking crypto_hash (1024 bytes)');
|
||||
var m = new Uint8Array(1024), out = new Uint8Array(64);
|
||||
for (i = 0; i < m.length; i++) m[i] = i & 255;
|
||||
benchmark(function(){
|
||||
nacl.lowlevel.crypto_hash(out, m, m.length);
|
||||
}, m.length);
|
||||
|
||||
log.start('Benchmarking crypto_hash (16 KiB)');
|
||||
m = new Uint8Array(16*1024);
|
||||
for (i = 0; i < m.length; i++) m[i] = i & 255;
|
||||
benchmark(function(){
|
||||
nacl.lowlevel.crypto_hash(out, m, m.length);
|
||||
}, m.length);
|
||||
}
|
||||
|
||||
crypto_stream_xor_benchmark();
|
||||
crypto_onetimeauth_benchmark();
|
||||
crypto_secretbox_benchmark();
|
||||
crypto_hash_benchmark();
|
||||
secretbox_seal_open_benchmark();
|
||||
crypto_scalarmult_base_benchmark();
|
||||
box_seal_open_benchmark();
|
||||
sign_open_benchmark();
|
||||
@ -1,62 +0,0 @@
|
||||
// Test helpers.
|
||||
(function(exports) {
|
||||
|
||||
function NodeLogger() {
|
||||
this.print = function() {
|
||||
console.log.apply(console, arguments);
|
||||
};
|
||||
|
||||
this.ok = function() {
|
||||
process.stdout.write('.');
|
||||
};
|
||||
|
||||
this.error = function() {
|
||||
console.error.apply(console, arguments);
|
||||
process.exit(1);
|
||||
};
|
||||
|
||||
this.start = this.print.bind(this, '\n');
|
||||
}
|
||||
|
||||
function BrowserLogger() {
|
||||
var el = document.createElement('pre');
|
||||
document.body.appendChild(el);
|
||||
|
||||
function escape(s) {
|
||||
var reps = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'/': '/'
|
||||
};
|
||||
return String(s).replace(/[&<>"'\/]/g, function (x) { return reps[x]; });
|
||||
}
|
||||
|
||||
this.print = function() {
|
||||
console.log.apply(console, arguments);
|
||||
var s = escape(arguments.length ? Array.prototype.slice.call(arguments).join(' ') : '');
|
||||
el.innerHTML += s + '\n';
|
||||
};
|
||||
|
||||
this.ok = function() {
|
||||
// No console output.
|
||||
el.innerHTML += '.';
|
||||
};
|
||||
|
||||
this.error = function() {
|
||||
console.error.apply(console, arguments);
|
||||
var s = escape(arguments.length ? Array.prototype.slice.call(arguments) : '');
|
||||
el.innerHTML += 'ERROR: ' + s + '\n';
|
||||
};
|
||||
|
||||
this.start = this.print.bind(this, '\n');
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined')
|
||||
exports.log = new BrowserLogger();
|
||||
else
|
||||
exports.log = new NodeLogger();
|
||||
|
||||
})(typeof exports !== 'undefined' ? exports : (window.helpers = window.helpers || {}));
|
||||
2
src/tweetnacl/test/browser/.gitignore
vendored
2
src/tweetnacl/test/browser/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
_bundle.js
|
||||
_bundle-quick.js
|
||||
@ -1,9 +0,0 @@
|
||||
This directory contains test files for browsers.
|
||||
|
||||
In the root project directory:
|
||||
|
||||
$ npm run browser
|
||||
|
||||
to build new _bundle.js.
|
||||
|
||||
Then open test.html.
|
||||
@ -1,11 +0,0 @@
|
||||
<!doctype html>
|
||||
<title>TweetNaCl.js Tests</title>
|
||||
<body>
|
||||
<h1>Select test to run:</h1>
|
||||
<ul>
|
||||
<li><a href="test.html"><b>Full</b> nacl.min.js</a></li>
|
||||
<li><a href="test-fast.html"><b>Full</b> nacl-fast.min.js</a></li>
|
||||
<li>--</li>
|
||||
<li><a href="test-quick.html"><b>Quick</b> nacl.min.js</a></li>
|
||||
<li><a href="test-quick-fast.html"><b>Quick</b> nacl-fast.min.js</a></li>
|
||||
</body>
|
||||
@ -1 +0,0 @@
|
||||
var _ = require('tap-browser-color')();
|
||||
@ -1,12 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>TweetNaCl-js Tests (fast)</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TweetNaCl-js Tests (fast)</h1>
|
||||
<script src="../../nacl-fast.min.js"></script>
|
||||
<script src="_bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,12 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>TweetNaCl-js Tests (fast)</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TweetNaCl-js Tests (fast)</h1>
|
||||
<script src="../../nacl-fast.min.js"></script>
|
||||
<script src="_bundle-quick.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,12 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>TweetNaCl-js Tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TweetNaCl-js Tests</h1>
|
||||
<script src="../../nacl.min.js"></script>
|
||||
<script src="_bundle-quick.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,12 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>TweetNaCl-js Tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TweetNaCl-js Tests</h1>
|
||||
<script src="../../nacl.min.js"></script>
|
||||
<script src="_bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1 +0,0 @@
|
||||
window.nacl = require('../../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
6
src/tweetnacl/test/c/.gitignore
vendored
6
src/tweetnacl/test/c/.gitignore
vendored
@ -1,6 +0,0 @@
|
||||
cscalarmult
|
||||
cbox
|
||||
csecretbox
|
||||
csign
|
||||
chash
|
||||
*.o
|
||||
@ -1,54 +0,0 @@
|
||||
var nacl = require('../../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var crypto = require('crypto');
|
||||
var spawn = require('child_process').spawn;
|
||||
var path = require('path');
|
||||
var test = require('tape');
|
||||
|
||||
function csecretbox(msg, n, k, callback) {
|
||||
var hexk = (new Buffer(k)).toString('hex');
|
||||
var hexn = (new Buffer(n)).toString('hex');
|
||||
var p = spawn(path.resolve(__dirname, 'csecretbox'), [hexk, hexn]);
|
||||
var result = [];
|
||||
p.stdout.on('data', function(data) {
|
||||
result.push(data);
|
||||
});
|
||||
p.on('close', function(code) {
|
||||
return callback(Buffer.concat(result).toString('base64'));
|
||||
});
|
||||
p.on('error', function(err) {
|
||||
throw err;
|
||||
});
|
||||
p.stdin.write(msg);
|
||||
p.stdin.end();
|
||||
}
|
||||
|
||||
test('nacl.secretbox (C)', function(t) {
|
||||
var k = new Uint8Array(nacl.secretbox.keyLength),
|
||||
n = new Uint8Array(nacl.secretbox.nonceLength),
|
||||
i;
|
||||
for (i = 0; i < 32; i++) k[i] = i;
|
||||
for (i = 0; i < 24; i++) n[i] = i;
|
||||
|
||||
function check(num, maxNum, next) {
|
||||
var msg = nacl.randomBytes(num);
|
||||
var box = nacl.util.encodeBase64(nacl.secretbox(msg, n, k));
|
||||
csecretbox(new Buffer(msg), n, k, function(boxFromC) {
|
||||
t.equal(box, boxFromC, 'secretboxes should be equal');
|
||||
t.notEqual(nacl.secretbox.open(nacl.util.decodeBase64(boxFromC), n, k), false, 'opening should succeed');
|
||||
if (num >= maxNum) {
|
||||
if (next) next();
|
||||
return;
|
||||
}
|
||||
check(num+1, maxNum, next);
|
||||
});
|
||||
}
|
||||
|
||||
check(0, 1024, function() {
|
||||
check(16418, 16500, function() {
|
||||
check(1000000, 0, function() {
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@ -1,44 +0,0 @@
|
||||
var NUMBER_OF_TESTS = 1000;
|
||||
|
||||
var nacl = require('../../' + (process.env.NACL_SRC || 'nacl.min.js'));
|
||||
var execFile = require('child_process').execFile;
|
||||
var path = require('path');
|
||||
var test = require('tape');
|
||||
|
||||
function cscalarmult(n, p, callback) {
|
||||
var hexN = (new Buffer(n)).toString('hex');
|
||||
var hexP = (new Buffer(p)).toString('hex');
|
||||
|
||||
execFile(path.resolve(__dirname, 'cscalarmult'), [hexN, hexP], function(err, stdout) {
|
||||
if (err) throw err;
|
||||
callback(stdout.toString('utf8'));
|
||||
});
|
||||
}
|
||||
|
||||
test('nacl.scalarMult (C)', function(t) {
|
||||
var k1 = {
|
||||
publicKey: nacl.util.decodeBase64('JRAWWRKVfZS2U/QiV+X2+PaabPfAB4H9p+BZkBN8ji8='),
|
||||
secretKey: nacl.util.decodeBase64('5g1pBmI3HL5GAjtt3/2FZDQVfGSMNohngN7OVSizBVE=')
|
||||
};
|
||||
|
||||
function check(num) {
|
||||
var k2 = nacl.box.keyPair();
|
||||
var q1 = nacl.scalarMult(k1.secretKey, k2.publicKey);
|
||||
var q2 = nacl.scalarMult(k2.secretKey, k1.publicKey);
|
||||
|
||||
t.equal(nacl.util.encodeBase64(q1), nacl.util.encodeBase64(q2),
|
||||
'scalarMult results should be equal');
|
||||
|
||||
hexQ = (new Buffer(q1)).toString('hex');
|
||||
cscalarmult(k1.secretKey, k2.publicKey, function(cQ) {
|
||||
t.equal(hexQ, cQ);
|
||||
if (num >= NUMBER_OF_TESTS) {
|
||||
t.end();
|
||||
return;
|
||||
}
|
||||
check(num+1);
|
||||
});
|
||||
}
|
||||
|
||||
check(0);
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user