mirror of
https://github.com/laurent22/joplin.git
synced 2026-05-07 20:02:45 +00:00
Co-authored-by: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
This commit is contained in:
@@ -1940,6 +1940,7 @@ packages/tools/update-readme-contributors.js
|
||||
packages/tools/update-readme-download.test.js
|
||||
packages/tools/update-readme-download.js
|
||||
packages/tools/update-readme-sponsors.js
|
||||
packages/tools/updateCanary.js
|
||||
packages/tools/updateMarkdownDoc.js
|
||||
packages/tools/utils/discourse.test.js
|
||||
packages/tools/utils/discourse.js
|
||||
|
||||
@@ -1913,6 +1913,7 @@ packages/tools/update-readme-contributors.js
|
||||
packages/tools/update-readme-download.test.js
|
||||
packages/tools/update-readme-download.js
|
||||
packages/tools/update-readme-sponsors.js
|
||||
packages/tools/updateCanary.js
|
||||
packages/tools/updateMarkdownDoc.js
|
||||
packages/tools/utils/discourse.test.js
|
||||
packages/tools/utils/discourse.js
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEaZWFlBYJKwYBBAHaRw8BAQdAIh3xQbjaS0EC+8WuKXNPjVF/ayq0/2GZlheR
|
||||
qj1G3Qe0RUpvcGxpbiBDYW5hcnkgU2lnbmluZyBLZXkgKFdhcnJhbnQgQ2FuYXJ5
|
||||
IEtleSkgPGNhbmFyeUBqb3BsaW5hcHAub3JnPoiZBBMWCgBBFiEE+CD4MG3QBaEC
|
||||
0YzVlGrp+lkV71MFAmmVhZQCGwMFCQPCZwAFCwkIBwICIgIGFQoJCAsCBBYCAwEC
|
||||
HgcCF4AACgkQlGrp+lkV71MZtwD/Ufd4OAcgkl5T6MSB+WDFg8BXvpaBZfNnZkoo
|
||||
LrOoqNAA/iqGiiBRoarlus2ATOiWhyXaEpRUQcEeaRhhqHW0BGcCuDgEaZWFlBIK
|
||||
KwYBBAGXVQEFAQEHQFORKWRLp4hDYzR8Q5IRyF9AIjoziR+sj4icUdvZx4Z6AwEI
|
||||
B4h+BBgWCgAmFiEE+CD4MG3QBaEC0YzVlGrp+lkV71MFAmmVhZQCGwwFCQPCZwAA
|
||||
CgkQlGrp+lkV71Nu+AD9Gw4qEmL8WNCNs7idc8CRpGpS2DhasNTV398lbKYzco0B
|
||||
ANlMrGlMc0w1KhuFxdU4fF3s/ktUUnjJwosxK94l5/MJ
|
||||
=C9VN
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
@@ -61,6 +61,14 @@ Name | Description
|
||||
|
||||
Please see the guide for information on how to contribute to the development of Joplin: https://github.com/laurent22/joplin/blob/dev/readme/dev/index.md
|
||||
|
||||
## Warrant Canary Signing Key
|
||||
|
||||
Fingerprint:
|
||||
|
||||
F820 F830 6DD0 05A1 02D1 8CD5 946A E9FA 5915 EF53
|
||||
|
||||
Public key: https://github.com/laurent22/joplin/raw/dev/Assets/keys/joplin-canary-signing-key.asc
|
||||
|
||||
# Contributors
|
||||
|
||||
Thank you to everyone who've contributed to Joplin's source code!
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"/readme/_i18n",
|
||||
"/readme/about/changelog/desktop.md",
|
||||
"/readme/licenses.md",
|
||||
"/readme/canary.txt",
|
||||
"/readme/i18n",
|
||||
"cspell.json",
|
||||
"node_modules"
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"test": "yarn workspaces foreach --worktree --parallel --verbose --interlaced --jobs 2 run test",
|
||||
"tsc": "yarn workspaces foreach --worktree --parallel --verbose --interlaced run tsc",
|
||||
"updateIgnored": "node packages/tools/gulp/tasks/updateIgnoredTypeScriptBuildRun.js",
|
||||
"updateCanary": "node ./packages/tools/updateCanary",
|
||||
"updateMarkdownDoc": "node ./packages/tools/updateMarkdownDoc",
|
||||
"updateNews": "node ./packages/tools/website/updateNews",
|
||||
"updatePluginTypes": "./packages/generator-joplin/updateTypes.sh",
|
||||
|
||||
@@ -250,4 +250,6 @@ mrjo
|
||||
codegen
|
||||
analyzed
|
||||
Perfetto
|
||||
appmodules
|
||||
appmodules
|
||||
armor
|
||||
clearsign
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import { execFileSync } from 'child_process';
|
||||
import { writeFile, remove } from 'fs-extra';
|
||||
import { dirname, join } from 'path';
|
||||
import { createInterface, Interface as ReadlineInterface } from 'readline';
|
||||
|
||||
const rootDir = dirname(dirname(__dirname));
|
||||
const canaryFile = join(rootDir, 'readme', 'canary.txt');
|
||||
|
||||
function formatDate(date: Date): string {
|
||||
const day = date.getUTCDate();
|
||||
const month = date.toLocaleString('en-US', { month: 'long', timeZone: 'UTC' });
|
||||
const year = date.getUTCFullYear();
|
||||
return `${day} ${month} ${year}`;
|
||||
}
|
||||
|
||||
function addDays(date: Date, days: number): Date {
|
||||
const result = new Date(date);
|
||||
result.setUTCDate(result.getUTCDate() + days);
|
||||
return result;
|
||||
}
|
||||
|
||||
function prompt(rl: ReadlineInterface, question: string): Promise<string> {
|
||||
return new Promise(resolve => {
|
||||
rl.question(question, answer => resolve(answer));
|
||||
});
|
||||
}
|
||||
|
||||
async function promptNonEmpty(rl: ReadlineInterface, question: string): Promise<string> {
|
||||
while (true) {
|
||||
const answer = (await prompt(rl, question)).trim();
|
||||
if (answer) return answer;
|
||||
console.log('This field cannot be empty. Please try again.');
|
||||
}
|
||||
}
|
||||
|
||||
function buildCanaryContent(statementDate: Date, headline1: string, headline2: string): string {
|
||||
const validUntil = addDays(statementDate, 60);
|
||||
return `Joplin Warrant Canary
|
||||
|
||||
Statement date: ${formatDate(statementDate)}
|
||||
Valid until: ${formatDate(validUntil)}
|
||||
|
||||
This warrant canary is updated every 60 days.
|
||||
If this document has not been updated within 75 days of the
|
||||
Statement date above, it should be considered expired.
|
||||
|
||||
As of the Statement date:
|
||||
|
||||
* No National Security Letters have been received by the project or its maintainer.
|
||||
* No orders under the USA PATRIOT Act or the Foreign Intelligence Surveillance Act have been received by the project or its maintainer.
|
||||
* No government request accompanied by a gag order has been received by the project or its maintainer.
|
||||
* No government agency or law enforcement body has required the introduction of backdoors into Joplin software, infrastructure, or services.
|
||||
* No government agency or law enforcement body has compelled the project or its maintainer to provide access to user data, servers, or infrastructure associated with Joplin.
|
||||
|
||||
If any such order is received, and we are legally permitted to do so,
|
||||
this statement will be updated accordingly. If we are not legally
|
||||
permitted to disclose the existence of such an order, this statement
|
||||
will not be updated.
|
||||
|
||||
The public key is available at:
|
||||
|
||||
https://github.com/laurent22/joplin/raw/dev/Assets/keys/joplin-canary-signing-key.asc
|
||||
|
||||
To prevent backdating, this statement includes current public events:
|
||||
|
||||
Current international events:
|
||||
|
||||
1. ${headline1}
|
||||
2. ${headline2}
|
||||
|
||||
Canary signing key fingerprint:
|
||||
|
||||
F820 F830 6DD0 05A1 02D1 8CD5 946A E9FA 5915 EF53
|
||||
`;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
try {
|
||||
console.log('Enter the current international event headlines to include in the canary.\n');
|
||||
const headline1 = await promptNonEmpty(rl, 'Headline 1: ');
|
||||
const headline2 = await promptNonEmpty(rl, 'Headline 2: ');
|
||||
|
||||
const statementDate = new Date();
|
||||
const content = buildCanaryContent(statementDate, headline1, headline2);
|
||||
|
||||
const tmpFile = `${canaryFile}.tmp`;
|
||||
await writeFile(tmpFile, content, 'utf8');
|
||||
execFileSync(
|
||||
'gpg',
|
||||
[
|
||||
'--yes',
|
||||
'--armor',
|
||||
'--clearsign',
|
||||
'--local-user',
|
||||
'canary@joplinapp.org',
|
||||
'--output',
|
||||
canaryFile,
|
||||
tmpFile,
|
||||
],
|
||||
{ stdio: 'inherit' },
|
||||
);
|
||||
await remove(tmpFile);
|
||||
|
||||
console.log(`Updated: ${canaryFile}`);
|
||||
} finally {
|
||||
rl.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(error => {
|
||||
console.error(error.message || error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
# Warrant Canary
|
||||
|
||||
This repository contains the official warrant canary for Joplin.
|
||||
|
||||
The purpose of the warrant canary is to provide a regularly updated, cryptographically signed statement indicating that no secret legal orders, gag orders, or similar directives have been received as of the stated date.
|
||||
|
||||
If such an order were ever received and disclosure were legally prohibited, the canary would cease to be updated.
|
||||
|
||||
## Location of the Canary
|
||||
|
||||
The current signed canary is published at:
|
||||
|
||||
https://github.com/laurent22/joplin/raw/dev/readme/canary.txt
|
||||
|
||||
## Canary Signing Key
|
||||
|
||||
The canary is signed using a dedicated OpenPGP key. It is linked from the canary.txt file.
|
||||
|
||||
Its fingerprint is present in the canary.txt file itself and duplicated at:
|
||||
|
||||
https://github.com/laurent22/joplin/blob/dev/README.md
|
||||
|
||||
## Updating the canary file
|
||||
|
||||
Run `yarn updateCanary` from the root of the repository and follow the prompt.
|
||||
|
||||
## Key Rotation Policy
|
||||
|
||||
The canary signing key may be rotated for the following reasons:
|
||||
|
||||
* Key expiry
|
||||
* Suspected compromise
|
||||
* Maintainer transition
|
||||
* Operational upgrades (e.g. hardware-backed signing)
|
||||
|
||||
Key rotation will never be performed silently.
|
||||
|
||||
## Key Rotation Procedure
|
||||
|
||||
### 1. Generate a New Key
|
||||
|
||||
Create a new dedicated OpenPGP signing key.
|
||||
|
||||
Export the new public key in ASCII-armoured format.
|
||||
|
||||
### 2. Publish the New Key
|
||||
|
||||
Add the new public key to:
|
||||
|
||||
https://github.com/laurent22/joplin/raw/dev/Assets/keys/joplin-canary-signing-key.asc
|
||||
|
||||
### 3. Update Documentation
|
||||
|
||||
#### Update the README
|
||||
|
||||
* Mark the new fingerprint as **Active**
|
||||
* Mark the previous fingerprint as **Retired**
|
||||
* Document the rotation date
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
Active Canary Signing Key:
|
||||
NEW FINGERPRINT
|
||||
|
||||
Previous Key (retired 2028-02-18):
|
||||
OLD FINGERPRINT
|
||||
```
|
||||
|
||||
#### Update updateCanary.ts
|
||||
|
||||
Add the new fingerprint to the canary template.
|
||||
|
||||
### 4. Transitional Signing
|
||||
|
||||
For the first canary issued after rotation:
|
||||
|
||||
* Sign with the new key
|
||||
* Optionally also sign with the old key
|
||||
|
||||
This creates a cryptographic bridge between the two identities.
|
||||
|
||||
If the old key is compromised, do not dual-sign. Instead, publish a revocation statement.
|
||||
@@ -0,0 +1,46 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA512
|
||||
|
||||
Joplin Warrant Canary
|
||||
|
||||
Statement date: 18 February 2026
|
||||
Valid until: 19 April 2026
|
||||
|
||||
This warrant canary is updated every 60 days.
|
||||
If this document has not been updated within 75 days of the
|
||||
Statement date above, it should be considered expired.
|
||||
|
||||
As of the Statement date:
|
||||
|
||||
* No National Security Letters have been received.
|
||||
* No orders under the USA PATRIOT Act have been received.
|
||||
* No orders under the Foreign Intelligence Surveillance Act have been received.
|
||||
* No government requests have been received that are accompanied by a gag order.
|
||||
* No law enforcement or government agency has required the introduction of backdoors into Joplin.
|
||||
|
||||
If any such order is received, and we are legally permitted to do so,
|
||||
this statement will be updated accordingly. If we are not legally
|
||||
permitted to disclose the existence of such an order, this statement
|
||||
will not be updated.
|
||||
|
||||
The public key is available at:
|
||||
|
||||
https://github.com/laurent22/joplin/blob/dev/Assets/keys/joplin-canary-signing-key.asc
|
||||
|
||||
To prevent backdating, this statement includes current public events:
|
||||
|
||||
Current international events:
|
||||
|
||||
1. Philippine vice-president Sara Duterte announces 2028 presidential bid
|
||||
2. African football chief ‘occupying seat illegally’ and must go, says leading executive
|
||||
|
||||
Canary signing key fingerprint:
|
||||
|
||||
F820 F830 6DD0 05A1 02D1 8CD5 946A E9FA 5915 EF53
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iIsEARYKADMWIQT4IPgwbdAFoQLRjNWUaun6WRXvUwUCaZWUBBUcY2FuYXJ5QGpv
|
||||
cGxpbmFwcC5vcmcACgkQlGrp+lkV71N8lwEAuRNboHOsr7/GbDjpEhkLrYOtzf2Y
|
||||
3uUBB3YBbPabWvEA/RNCb0sUqFaKUT8Zeq/IsoLydsRsLMYUaUP19WIS/rQM
|
||||
=UEz2
|
||||
-----END PGP SIGNATURE-----
|
||||
Reference in New Issue
Block a user