Checksums - Allow anyone to confirm source and delivered code (#467)

* Checksums - Allow anyone to confirm source and delivered code

For now this only has the initial step on making CSP stricter so we can use it to parse through used files.

Very much WIP for now, but now it should just be a matter of writing up concise docs on how to go through the process, after generating and publishing the checksums via CI as well.

Related to #331

* Lint!

* Add more instructions and CI to build checksums.

* Fix typo and lint

* Remove CSP package dependency, build it manually.

Update commands in docs, fix web extension release.

* Tweak docs and webpack. CI still isn't producing a matching checksum, though.

* Tweak docs for web checksums, add debugging in the checksum action, make it faster, temporarily.

* Fix web checksum, add checksums and instructions for everything else

Closes #467

* Fix tauri release + macos sha256sum

* Remove .app checksum, since it's a directory and checksum'ing the .tar.gz seems strange.

* Properly indent + fix sha256sum results (and windows line endings problem)

* Include PWA for release, add instructions to change filenames when checksum fails.

* Include _everything_ in the CSP now, and tweak the verification script and checksum build to also include everything, now.

Still requires changes in the way to verify a published web app, where I'll have to write a script to parse through the whole CSP now.

* Add TypeScript (Deno) script to parse through CSP and download matched files.

Also update docs.

* Tweak web checksum examples.

* Remove content hashes from font files.

* Try sorting files before adding to CSP, to enforce consistency.
This commit is contained in:
Bruno Bernardino 2022-06-20 07:34:45 +01:00 committed by GitHub
parent ea05def083
commit 8e2036f297
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 21628 additions and 20018 deletions

View File

@ -81,7 +81,7 @@ jobs:
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/extension/dist/web-ext-artifacts/padloc-${{ env.PL_VENDOR_VERSION }}.${{ env.RELEASE_BUILD }}-an+fx.xpi
file: packages/extension/dist/web-ext-artifacts/padloc-${{ env.PL_VENDOR_VERSION }}.${{ env.RELEASE_BUILD }}.xpi
asset_name: padloc-web-extension-${{ env.PL_VENDOR_VERSION }}.${{ env.RELEASE_BUILD }}.xpi
prerelease: true
- name: Pack for Chrome Extension
@ -112,6 +112,30 @@ jobs:
file: packages/extension/padloc-signed.crx
asset_name: padloc-web-extension-${{ env.PL_VENDOR_VERSION }}.${{ env.RELEASE_BUILD }}.crx
prerelease: true
- name: Generate checksum (xpi)
run: |
cd packages/extension/dist/web-ext-artifacts
sha256sum padloc*.xpi > sha256sum-xpi.txt
- name: Upload checksum (xpi)
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/extension/dist/web-ext-artifacts/sha256sum-xpi.txt
asset_name: sha256sum-xpi.txt
prerelease: true
- name: Generate checksum (crx)
run: |
cd packages/extension
sha256sum padloc-signed.crx > sha256sum-crx.txt
- name: Upload checksum (crx)
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/extension/sha256sum-crx.txt
asset_name: sha256sum-crx.txt
prerelease: true
release_tauri:
name: "Release Tauri apps"
@ -143,11 +167,15 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0
- name: Install coreutils
if: matrix.platform == 'macos-latest'
run: |
brew install coreutils
- name: Install dependencies
run: |
npm i -g npm@8.2.0
npm ci
- uses: tauri-apps/tauri-action@v0.2.0
- uses: tauri-apps/tauri-action@v0.3.1
env:
PL_SERVER_URL: ${{ secrets.PL_SERVER_URL }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@ -162,6 +190,62 @@ jobs:
with:
releaseId: ${{ env.RELEASE_ID }}
projectPath: packages/tauri
- name: Generate checksum (AppImage)
if: matrix.platform == 'ubuntu-latest'
run: |
cd packages/tauri/src-tauri/target/release/bundle/appimage
sha256sum padloc*.AppImage > sha256sum-appimage.txt
- name: Upload checksum (AppImage)
if: matrix.platform == 'ubuntu-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/tauri/src-tauri/target/release/bundle/appimage/sha256sum-appimage.txt
asset_name: sha256sum-tauri-appimage.txt
prerelease: true
- name: Generate checksum (deb)
if: matrix.platform == 'ubuntu-latest'
run: |
cd packages/tauri/src-tauri/target/release/bundle/deb
sha256sum *.deb > sha256sum-deb.txt
- name: Upload checksum (deb)
if: matrix.platform == 'ubuntu-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/tauri/src-tauri/target/release/bundle/deb/sha256sum-deb.txt
asset_name: sha256sum-tauri-deb.txt
prerelease: true
- name: Generate checksum (dmg)
if: matrix.platform == 'macos-latest'
run: |
cd packages/tauri/src-tauri/target/release/bundle/dmg
sha256sum *.dmg > sha256sum-dmg.txt
- name: Upload checksum (dmg)
if: matrix.platform == 'macos-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/tauri/src-tauri/target/release/bundle/dmg/sha256sum-dmg.txt
asset_name: sha256sum-tauri-dmg.txt
prerelease: true
- name: Generate checksum (msi)
if: matrix.platform == 'windows-latest'
run: |
cd packages/tauri/src-tauri/target/release/bundle/msi
sha256sum *.msi > sha256sum-msi.txt
- name: Upload checksum (msi)
if: matrix.platform == 'windows-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/tauri/src-tauri/target/release/bundle/msi/sha256sum-msi.txt
asset_name: sha256sum-tauri-msi.txt
prerelease: true
release_electron:
name: "Release Electron apps"
@ -182,6 +266,10 @@ jobs:
- uses: actions/setup-node@v2
with:
node-version-file: ".nvmrc"
- name: Install coreutils
if: matrix.platform == 'macos-latest'
run: |
brew install coreutils
- name: Install dependencies
run: |
npm i -g npm@8.2.0
@ -197,6 +285,48 @@ jobs:
PL_MACOS_NOTARIZE_PASSWORD: ${{ secrets.PL_MACOS_NOTARIZE_PASSWORD }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
EP_PRE_RELEASE: true
- name: Generate checksum (AppImage)
if: matrix.platform == 'ubuntu-latest'
run: |
cd packages/electron/dist
sha256sum *.AppImage > sha256sum-appimage.txt
- name: Upload checksum (AppImage)
if: matrix.platform == 'ubuntu-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/electron/dist/sha256sum-appimage.txt
asset_name: sha256sum-electron-appimage.txt
prerelease: true
- name: Generate checksum (dmg)
if: matrix.platform == 'macos-latest'
run: |
cd packages/electron/dist
sha256sum *.dmg > sha256sum-dmg.txt
- name: Upload checksum (dmg)
if: matrix.platform == 'macos-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/electron/dist/sha256sum-dmg.txt
asset_name: sha256sum-electron-dmg.txt
prerelease: true
- name: Generate checksum (exe)
if: matrix.platform == 'windows-latest'
run: |
cd packages/electron/dist
sha256sum *.exe > sha256sum-exe.txt
- name: Upload checksum (exe)
if: matrix.platform == 'windows-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/electron/dist/sha256sum-exe.txt
asset_name: sha256sum-electron-exe.txt
prerelease: true
release_cordova:
name: "Release Cordova apps"
@ -230,6 +360,10 @@ jobs:
- uses: actions/setup-node@v2
with:
node-version-file: ".nvmrc"
- name: Install coreutils
if: matrix.platform == 'macos-latest'
run: |
brew install coreutils
- name: Install dependencies
run: |
npm i -g npm@8.2.0
@ -315,6 +449,34 @@ jobs:
file: packages/cordova/platforms/ios/build/device/Padloc.ipa
asset_name: padloc-${{ env.PL_VENDOR_VERSION }}.ipa
prerelease: true
- name: Generate checksum (apk)
if: matrix.platform == 'ubuntu-latest'
run: |
cd packages/cordova/platforms/android/app/build/outputs/apk/release
sha256sum app-release.apk > sha256sum-apk.txt
- name: Upload checksum (apk)
if: matrix.platform == 'ubuntu-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/cordova/platforms/android/app/build/outputs/apk/release/sha256sum-apk.txt
asset_name: sha256sum-apk.txt
prerelease: true
- name: Generate checksum (ipa)
if: matrix.platform == 'macos-latest'
run: |
cd packages/cordova/platforms/ios/build/device
sha256sum Padloc.ipa > sha256sum-ipa.txt
- name: Upload checksum (ipa)
if: matrix.platform == 'macos-latest'
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/cordova/platforms/ios/build/device/sha256sum-ipa.txt
asset_name: sha256sum-ipa.txt
prerelease: true
- name: Delete android-upload-key.keystore
if: matrix.platform == 'ubuntu-latest' && always()
run: rm -f ./packages/cordova/android-upload-key.keystore
@ -323,3 +485,60 @@ jobs:
run: |
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
rm -f ~/Library/MobileDevice/Provisioning\ Profiles/build_pp.mobileprovision
release_web_checksums:
name: "Release web checksums"
environment: ${{ github.event.inputs.environment || 'Beta' }}
needs: create_release_tag
env:
RELEASE_ID: ${{ needs.create_release_tag.outputs.release_id }}
PL_VENDOR_VERSION: ${{ github.event.inputs.vendor_version || '0.0.1' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version-file: ".nvmrc"
- name: Install dependencies
run: |
npm i -g npm@8.2.0
npm ci
- name: Build
run: |
npm run pwa:build
env:
PL_PWA_URL: ${{ secrets.PL_PWA_URL }}
PL_SERVER_URL: ${{ secrets.PL_SERVER_URL }}
- name: Generate pwa.tar.gz
run: |
cd packages/pwa/dist
tar -czf ../pwa.tar.gz *
- name: Upload pwa.tar.gz
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/pwa/pwa.tar.gz
asset_name: padloc-pwa-${{ env.PL_VENDOR_VERSION }}.${{ env.RELEASE_BUILD }}.tar.gz
prerelease: true
- name: Generate checksums
run: |
cd packages/pwa/dist
find . -type f ! -name "sha256sums-web.txt" -exec sha256sum {} > sha256sums-web.txt \;
- name: Upload checksums
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: packages/pwa/dist/sha256sums-web.txt
asset_name: sha256sums-web.txt
prerelease: true
- name: Upload CSP parser
uses: svenstaro/upload-release-action@2.2.1
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: "v${{ env.PL_VENDOR_VERSION }}"
file: docs/checksums/web/parse-csp.ts
asset_name: parse-csp.ts
prerelease: true

View File

@ -4,5 +4,9 @@
"*.svg": "html"
},
"prettier.prettierPath": "./node_modules/prettier",
"files.insertFinalNewline": true
"files.insertFinalNewline": true,
"deno.enable": false,
"deno.lint": true,
"deno.unstable": true,
"deno.enablePaths": ["./docs/checksums/web"]
}

19
docs/checksums/README.md Normal file
View File

@ -0,0 +1,19 @@
# Checksums
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
In here you can find ways to verify the checksums for the different platforms:
- [Web](web)
- [Firefox](firefox)
- [Chrome](chrome)
- [Android](android)
- [iOS](ios)
- [Linux](linux)
- [macOS](macos)
- [Windows](windows)

View File

@ -0,0 +1,61 @@
# Checksums (Android)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
Unfortunately, because we sign our Android builds, it's not really possible to
locally build the exact same file unless you had access to our certificates and
keys. You can still
[see how we build them here](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L201),
and
[see how to build unsigned ones yourself](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-cordova.yml),
though.
## Verify what you're using has the same source code
1. Download the apk file.
You can do that from
[our releases page](https://github.com/padloc/padloc/releases) or from the
store you've downloaded it from, to make sure that wasn't tampered with in
the process of uploading there.
2. Download the latest `sha256sum-apk.txt` checksum file:
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sum-apk.txt
```
3. Verify checksum matches:
```bash
sha256sum -c sha256sum-apk.txt
```
You should see the `.apk` filename with an `OK` next to it for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
> **NOTE:** If there's a warning about failing to find a file, your `.apk`
> file probably doesn't match what `sha256sum-apk.txt` expects, so you can
> change your `.apk` file's name to `app-release.apk` (or whatever's in the
> file) for it to be found.
Here's an illustrative example of success:
```txt
./app-release.apk: OK
```
And one with a tampered file:
```txt
./app-release.apk: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
```

View File

@ -0,0 +1,61 @@
# Checksums (Chrome)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
Unfortunately, because we sign our Chrome builds, it's not really possible to
locally build the exact same file unless you had access to our certificates and
keys. You can still
[see how we build them here](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L54),
and
[see how to build unsigned ones yourself](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-web-extension.yml),
though.
## Verify what you're using has the same source code
1. Download the crx file.
You can do that from
[our releases page](https://github.com/padloc/padloc/releases) or from the
store you've downloaded it from, to make sure that wasn't tampered with in
the process of uploading there.
2. Download the latest `sha256sum-crx.txt` checksum file:
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sum-crx.txt
```
3. Verify checksum matches:
```bash
sha256sum -c sha256sum-crx.txt
```
You should see the `.xpi` filename with an `OK` next to it for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
> **NOTE:** If there's a warning about failing to find a file, your `.crx`
> file probably doesn't match what `sha256sum-crx.txt` expects, so you can
> change your `.crx` file's name to `padloc-signed.crx` (or whatever's in
> the file) for it to be found.
Here's an illustrative example of success:
```txt
./padloc-signed.crx: OK
```
And one with a tampered file:
```txt
./padloc-signed.crx: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
```

View File

@ -0,0 +1,61 @@
# Checksums (Firefox)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
Unfortunately, because we sign our Firefox builds, it's not really possible to
locally build the exact same file unless you had access to our certificates and
keys. You can still
[see how we build them here](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L54),
and
[see how to build unsigned ones yourself](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-web-extension.yml),
though.
## Verify what you're using has the same source code
1. Download the xpi file.
You can do that from
[our releases page](https://github.com/padloc/padloc/releases) or from the
store you've downloaded it from, to make sure that wasn't tampered with in
the process of uploading there.
2. Download the latest `sha256sum-xpi.txt` checksum file:
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sum-xpi.txt
```
3. Verify checksum matches:
```bash
sha256sum -c sha256sum-xpi.txt
```
You should see the `.xpi` filename with an `OK` next to it for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
> **NOTE:** If there's a warning about failing to find a file, your `.xpi`
> file probably doesn't match what `sha256sum-xpi.txt` expects, so you can
> change your `.xpi` file's name to `padloc-4.0.0.55.xpi` (or whatever's in
> the file) for it to be found.
Here's an illustrative example of success:
```txt
./padloc-4.0.0.55.xpi: OK
```
And one with a tampered file:
```txt
./padloc-4.0.0.55.xpi: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
```

View File

@ -0,0 +1,61 @@
# Checksums (iOS)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
Unfortunately, because we sign our iOS builds, it's not really possible to
locally build the exact same file unless you had access to our certificates and
keys. You can still
[see how we build them here](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L201),
and
[see how to build unsigned ones yourself](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-cordova.yml),
though.
## Verify what you're using has the same source code
1. Download the ipa file.
You can do that from
[our releases page](https://github.com/padloc/padloc/releases) or from the
store you've downloaded it from, to make sure that wasn't tampered with in
the process of uploading there.
2. Download the latest `sha256sum-ipa.txt` checksum file:
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sum-ipa.txt
```
3. Verify checksum matches:
```bash
sha256sum -c sha256sum-ipa.txt
```
You should see the `.ipa` filename with an `OK` next to it for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
> **NOTE:** If there's a warning about failing to find a file, your `.ipa`
> file probably doesn't match what `sha256sum-ipa.txt` expects, so you can
> change your `.ipa` file's name to `Padloc.ipa` (or whatever's in the file)
> for it to be found.
Here's an illustrative example of success:
```txt
./Padloc.ipa: OK
```
And one with a tampered file:
```txt
./Padloc.ipa: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
```

View File

@ -0,0 +1,72 @@
# Checksums (Linux)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
Unfortunately, because we sign our Linux builds (both via Electron and Tauri),
it's not really possible to locally build the exact same file unless you had
access to our certificates and keys. You can still see how we build them here
([via Electron](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L166)
and
[via Tauri](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L116)),
and see how to build unsigned ones yourself
([via Electron](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-electron.yml)
and
[via Tauri](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-tauri.yml))
, though.
## Verify what you're using has the same source code
1. Download the Electron or Tauri AppImage or deb file.
You can do that from
[our releases page](https://github.com/padloc/padloc/releases) or from the
store you've downloaded it from, to make sure that wasn't tampered with in
the process of uploading there.
2. Download the latest `sha256sum-[tauri/electron]-[appimage/deb].txt` checksum
file:
**NOTE**: Pick one of the options above, from `tauri` or `electron`, and
from `appimage` or `deb`, depending on what's available for that platform.
You can see what's available in the releases page. For the examples below,
we'll use `tauri` and `appimage`.
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sum-tauri-appimage.txt
```
3. Verify checksum matches:
```bash
sha256sum -c sha256sum-tauri-appimage.txt
```
You should see the `.AppImage` filename with an `OK` next to it for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
> **NOTE:** If there's a warning about failing to find a file, your
> `.AppImage` file probably doesn't match what
> `sha256sum-tauri-appimage.txt` expects, so you can change your `.AppImage`
> file's name to `padloc_4.0.0_amd64.AppImage` (or whatever's in the file)
> for it to be found.
Here's an illustrative example of success:
```txt
./padloc_4.0.0_amd64.AppImage: OK
```
And one with a tampered file:
```txt
./padloc_4.0.0_amd64.AppImage: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
```

View File

@ -0,0 +1,68 @@
# Checksums (macOS)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
Unfortunately, because we sign our macOS builds (both via Electron and Tauri),
it's not really possible to locally build the exact same file unless you had
access to our certificates and keys. You can still see how we build them here
([via Electron](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L166)
and
[via Tauri](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L116)),
and see how to build unsigned ones yourself
([via Electron](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-electron.yml)
and
[via Tauri](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-tauri.yml))
, though.
## Verify what you're using has the same source code
1. Download the Electron or Tauri dmg or app file.
You can do that from
[our releases page](https://github.com/padloc/padloc/releases) or from the store
you've downloaded it from, to make sure that wasn't tampered with in the process
of uploading there.
2. Download the latest `sha256sum-[tauri/electron]-dmg.txt` checksum file:
**NOTE**: Pick one of the options above, from `tauri` or `electron`. For the
examples below, we'll use `tauri`.
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sum-tauri-dmg.txt
```
3. Verify checksum matches:
```bash
sha256sum -c sha256sum-tauri-dmg.txt
```
You should see the `.dmg` filename with an `OK` next to it for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
> **NOTE:** If there's a warning about failing to find a file, your `.dmg`
> file probably doesn't match what `sha256sum-tauri-dmg.txt` expects, so you
> can change your `.dmg` file's name to `Padloc_4.0.0_x64.dmg` (or
> whatever's in the file) for it to be found.
Here's an illustrative example of success:
```txt
./Padloc_4.0.0_x64.dmg: OK
```
And one with a tampered file:
```txt
./Padloc_4.0.0_x64.dmg: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
```

View File

@ -0,0 +1,196 @@
# Checksums (Web)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
1. Clone repo and install dependencies:
```bash
git clone git@github.com:padloc/padloc.git && \
cd padloc && \
git pull origin/v4 && \
npm install
```
2. Build code (replace `beta.padloc.app` with whatever domain you're trying to
check, if not padloc's production):
```bash
PL_PWA_URL=https://beta.padloc.app \
PL_SERVER_URL=$PL_PWA_URL/server/ \
npm run pwa:build
```
3. Download the latest `sha256sums-web.txt` checksum file:
```bash
cd packages/pwa/dist && \
wget https://github.com/padloc/padloc/releases/latest/download/sha256sums-web.txt
```
4. Verify checksums match:
```bash
sha256sum -c sha256sums-web.txt
```
You should see all filenames with an `OK` next to them for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
Here's an illustrative example of success:
```txt
./main.js: OK
./9c5a939648cf4e10869c369c7262c0b2.woff2: OK
./0ce7bb41cbc2ad09a21b7b5222628111.svg: OK
./zxcvbn.chunk.js: OK
./manifest.623e2268f17398ec7f19225e281e4056.json: OK
./ua-parser.chunk.js: OK
./locale_res_wordlists_pt_json.chunk.js: OK
./locale_res_wordlists_en_json.chunk.js: OK
./sw.js.map: OK
./app_src_elements_app_ts.chunk.js.map: OK
./index.html: OK
./ua-parser.chunk.js.map: OK
./6d964ac2439b4e11afd25d1d47df88b6.woff2: OK
./56435da2448caaff95b05759954ec6ee.woff2: OK
./icon_192x192.8dfb7236c7e6b6591567173b18eaa144.png: OK
./vendors-app_node_modules_autosize_src_autosize_js-app_node_modules_dompurify_dist_purify_js-a-10f8da.chunk.js.map: OK
./app_src_elements_app_ts.chunk.js: OK
./sw.js: OK
./main.js.map: OK
./icon_384x384.971e45062e4d601a3014dc16ee3ed27b.png: OK
./locale_res_translations_fr_json.chunk.js: OK
./c94db5f3862667362c6815c9b1ec8acf.woff2: OK
./icon_256x256.9a47fba2857d94939047064f37cd075f.png: OK
./locale_res_translations_pl_json.chunk.js: OK
./locale_res_translations_es_json.chunk.js: OK
./locale_res_translations_de_json.chunk.js: OK
./zxcvbn.chunk.js.map: OK
./locale_res_translations_ru_json.chunk.js: OK
./papaparse.chunk.js.map: OK
./5d40dd64e2278fe436ba68ac7f1195a4.woff2: OK
./jsqr.chunk.js.map: OK
./1bbee3bd1bc00c4dce2a7c7046930ae6.woff2: OK
./app_src_lib_1pux-parser_ts.chunk.js.map: OK
./vendors-app_node_modules_date-fns_esm_sub_index_js.chunk.js: OK
./locale_res_wordlists_de_json.chunk.js: OK
./favicon.png: OK
./icon_128x128.f620784d1682c9fbb033d3b018e7d998.png: OK
./vendors-app_node_modules_autosize_src_autosize_js-app_node_modules_dompurify_dist_purify_js-a-10f8da.chunk.js: OK
./app_src_lib_1pux-parser_ts.chunk.js: OK
./papaparse.chunk.js: OK
./icon_512x512.e3175643e8fe0d95175a493da5201480.png: OK
./4a9ab29a10089191088de2b7c02c78e7.woff2: OK
./locale_res_wordlists_es_json.chunk.js: OK
./locale_res_translations__template_json.chunk.js: OK
./vendors-app_node_modules_date-fns_esm_sub_index_js.chunk.js.map: OK
./locale_res_wordlists_fr_json.chunk.js: OK
./icon_96x96.eda9f98be1c35dabab77f9d2ab7be538.png: OK
./5ce2631c76a09ec2ab1d619e3b1eda91.woff2: OK
./jsqr.chunk.js: OK
./b1fac335d3804d9dadf795e093048b40.woff2: OK
./03e3c10d4a52fe7b56918f851766d886.woff2: OK
./date-fns.chunk.js.map: OK
./date-fns.chunk.js: OK
```
And one with a tampered `main.js` file:
```txt
./main.js: FAILED
./9c5a939648cf4e10869c369c7262c0b2.woff2: OK
./0ce7bb41cbc2ad09a21b7b5222628111.svg: OK
./zxcvbn.chunk.js: OK
./manifest.623e2268f17398ec7f19225e281e4056.json: OK
./ua-parser.chunk.js: OK
./locale_res_wordlists_pt_json.chunk.js: OK
./locale_res_wordlists_en_json.chunk.js: OK
./sw.js.map: OK
./app_src_elements_app_ts.chunk.js.map: OK
./index.html: OK
./ua-parser.chunk.js.map: OK
./6d964ac2439b4e11afd25d1d47df88b6.woff2: OK
./56435da2448caaff95b05759954ec6ee.woff2: OK
./icon_192x192.8dfb7236c7e6b6591567173b18eaa144.png: OK
./vendors-app_node_modules_autosize_src_autosize_js-app_node_modules_dompurify_dist_purify_js-a-10f8da.chunk.js.map: OK
./app_src_elements_app_ts.chunk.js: OK
./sw.js: OK
./main.js.map: OK
./icon_384x384.971e45062e4d601a3014dc16ee3ed27b.png: OK
./locale_res_translations_fr_json.chunk.js: OK
./c94db5f3862667362c6815c9b1ec8acf.woff2: OK
./icon_256x256.9a47fba2857d94939047064f37cd075f.png: OK
./locale_res_translations_pl_json.chunk.js: OK
./locale_res_translations_es_json.chunk.js: OK
./locale_res_translations_de_json.chunk.js: OK
./zxcvbn.chunk.js.map: OK
./locale_res_translations_ru_json.chunk.js: OK
./papaparse.chunk.js.map: OK
./5d40dd64e2278fe436ba68ac7f1195a4.woff2: OK
./jsqr.chunk.js.map: OK
./1bbee3bd1bc00c4dce2a7c7046930ae6.woff2: OK
./app_src_lib_1pux-parser_ts.chunk.js.map: OK
./vendors-app_node_modules_date-fns_esm_sub_index_js.chunk.js: OK
./locale_res_wordlists_de_json.chunk.js: OK
./favicon.png: OK
./icon_128x128.f620784d1682c9fbb033d3b018e7d998.png: OK
./vendors-app_node_modules_autosize_src_autosize_js-app_node_modules_dompurify_dist_purify_js-a-10f8da.chunk.js: OK
./app_src_lib_1pux-parser_ts.chunk.js: OK
./papaparse.chunk.js: OK
./icon_512x512.e3175643e8fe0d95175a493da5201480.png: OK
./4a9ab29a10089191088de2b7c02c78e7.woff2: OK
./locale_res_wordlists_es_json.chunk.js: OK
./locale_res_translations__template_json.chunk.js: OK
./vendors-app_node_modules_date-fns_esm_sub_index_js.chunk.js.map: OK
./locale_res_wordlists_fr_json.chunk.js: OK
./icon_96x96.eda9f98be1c35dabab77f9d2ab7be538.png: OK
./5ce2631c76a09ec2ab1d619e3b1eda91.woff2: OK
./jsqr.chunk.js: OK
./b1fac335d3804d9dadf795e093048b40.woff2: OK
./03e3c10d4a52fe7b56918f851766d886.woff2: OK
./date-fns.chunk.js.map: OK
./date-fns.chunk.js: OK
sha256sum: WARNING: 1 computed checksum did NOT match
```
## Verify what you're using has the same source code
1. Download a website (replace `beta.padloc.app` with whatever domain you're
trying to check), and all the relevant files:
```bash
HOST_TO_CHECK=beta.padloc.app && \
wget -r -p -U Mozilla https://$HOST_TO_CHECK && \
cd $HOST_TO_CHECK && \
wget https://github.com/padloc/padloc/releases/latest/download/parse-csp.ts && \
deno run --allow-read=index.html --allow-net=$HOST_TO_CHECK --allow-write=. parse-csp.ts
```
The bash script above downloads a full website into a directory with its
hostname, then parses the `Content-Security-Policy` meta tag to get the list
of all the used/necessary files (using [`Deno`](https://deno.land), after
downloading the [`parse-csp.ts`](parse-csp.ts) file from this repo). This
will change with each build of Padloc, so the script needs to be dynamic.
2. Download the latest `sha256sums-web.txt` checksum file:
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sums-web.txt
```
3. Verify checksums match:
```bash
sha256sum -c sha256sums-web.txt
```
You can see step 4 from the `Verify checksums against source code` section
above, for expected outputs.

View File

@ -0,0 +1,79 @@
import { writableStreamFromWriter } from "https://deno.land/std@0.143.0/streams/mod.ts";
const indexFileName = "index.html";
const html = await Deno.readTextFile(`./${indexFileName}`);
const regExp = /(?:<meta http-equiv="Content-Security-Policy" content=")([^">]+)">/gi;
const matches = regExp.exec(html);
if (!matches || !matches[1]) {
console.error("Could not find CSP meta tag. Please make sure you've downloaded a correct index.html file.");
Deno.exit(1);
}
console.log("Found CSP meta tag. Parsing rules...");
const cspString = matches[1];
const filesInCsp = new Set<string>();
const cspRuleStrings = cspString.split(";").map((cspRule) => cspRule.trim());
// Parse all rules appropriately, with the files per rule
for (const cspRuleString of cspRuleStrings) {
const cspParts = cspRuleString.split(" ");
if (cspParts.length === 0) {
console.error("Found invalid CSP rule. Please make sure you've downloaded a correct index.html file.");
Deno.exit(1);
}
// Skip empty set (we get one at the end)
if (cspParts.length === 1 && cspParts[0] === "") {
continue;
}
// Remove the rule name
cspParts.shift();
for (const cspPart of cspParts) {
if (cspPart.startsWith("https://")) {
// Confirm we're downloading a file and not a server URL, for example
const urlParts = cspPart.split("/");
const fileName = urlParts.pop() || "";
const fileExtension = fileName.split(".").pop();
if (urlParts.length > 2 && fileName && fileExtension) {
filesInCsp.add(cspPart);
}
}
}
}
console.log("Parsed all the rules. Downloading files...");
// Download all files, in parallel
await Promise.all(
Array.from(filesInCsp).map(async (fileUrl) => {
try {
const fileName = fileUrl.split("/").pop() || "";
const response = await fetch(fileUrl);
// Stream instead of waiting for the response to finish before saving, as it's faster, even if the files should be small
if (response.body) {
const file = await Deno.open(`./${fileName}`, { write: true, create: true });
const writableStream = writableStreamFromWriter(file);
await response.body.pipeTo(writableStream);
} else {
throw new Error("Failed to fetch file");
}
} catch (error) {
console.error(`Failed to download "${fileUrl}": ${error}`);
}
})
);
console.log(
"Finished downloading files. You can now download the latest checksum and run the sha256sum command to verify them."
);

View File

@ -0,0 +1,72 @@
# Checksums (Windows)
We use file checksums (SHA-256) to verify the source code you see matches the
code served by our app. These are instructions for you to verify that too, so
you don't have to trust us.
**NOTE:** These commands are meant for Linux and should also work on macOS. For
Windows systems, we suggest you run them via WSL2.
## Verify checksums against source code
Unfortunately, because we sign our Windows builds (both via Electron and Tauri),
it's not really possible to locally build the exact same file unless you had
access to our certificates and keys. You can still see how we build them here
([via Electron](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L166)
and
[via Tauri](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/publish-release.yml#L116)),
and see how to build unsigned ones yourself
([via Electron](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-electron.yml)
and
[via Tauri](https://github.com/padloc/padloc/blob/ea05def083df89823d7c15c7bbeb6ef1a1b40383/.github/workflows/build-tauri.yml))
, though.
## Verify what you're using has the same source code
1. Download the Electron or Tauri exe or msi file.
You can do that from
[our releases page](https://github.com/padloc/padloc/releases) or from the
store you've downloaded it from, to make sure that wasn't tampered with in
the process of uploading there.
2. Download the latest `sha256sum-[tauri/electron]-[exe/msi].txt` checksum file:
**NOTE**: Pick one of the options above, from `tauri` or `electron`, and
from `exe` or `msi`, depending on what's available for that platform. You
can see what's available in the releases page. For the examples below, we'll
use `tauri` and `msi`.
```bash
wget https://github.com/padloc/padloc/releases/latest/download/sha256sum-tauri-msi.txt
```
3. Verify checksum matches:
```bash
# replaces windows line-endings with unix
sed -i.bak 's/\r$//' sha256sum-tauri-msi.txt && \
sha256sum -c sha256sum-tauri-msi.txt
```
You should then see the `.msi` filename with an `OK` next to it for matching
checksums. You'll get a warning at the end of the script if something didn't
match.
> **NOTE:** If there's a warning about failing to find a file, your `.msi`
> file probably doesn't match what `sha256sum-tauri-msi.txt` expects, so you
> can change your `.msi` file's name to `Padloc_4.0.0_x64_en-US.msi` (or
> whatever's in the file) for it to be found.
Here's an illustrative example of success:
```txt
./Padloc_4.0.0_x64_en-US.msi: OK
```
And one with a tampered file:
```txt
./Padloc_4.0.0_x64_en-US.msi: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match
```

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@ const sharp = require("sharp");
const out = process.env.PL_PWA_DIR || resolve(__dirname, "dist");
const serverUrl = process.env.PL_SERVER_URL || `http://0.0.0.0:${process.env.PL_SERVER_PORT || 3000}`;
const pwaUrl = process.env.PL_PWA_URL || `http://localhost:${process.env.PL_PWA_PORT || 8080}`;
const rootDir = resolve(__dirname, "../..");
const assetsDir = resolve(rootDir, process.env.PL_ASSETS_DIR || "assets");
@ -54,6 +55,7 @@ module.exports = {
plugins: [
new EnvironmentPlugin({
PL_APP_NAME: name,
PL_PWA_URL: pwaUrl,
PL_SERVER_URL: serverUrl,
PL_BILLING_ENABLED: null,
PL_BILLING_DISABLE_PAYMENT: null,
@ -66,13 +68,96 @@ module.exports = {
PL_TERMS_OF_SERVICE: terms_of_service,
}),
new CleanWebpackPlugin(),
{
apply(compiler) {
compiler.hooks.compilation.tap("Store Built Files for CSP", (compilation) => {
HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(
"Store Built Files for CSP",
(data, callback) => {
const isBuildingLocally = pwaUrl.startsWith("http://localhost");
const fileExtensionsToCspRule = new Map([
["js", "script-src"],
["map", "script-src"],
["woff2", "font-src"],
["svg", "img-src"],
["png", "img-src"],
]);
const builtFilesForCsp = new Map([
["script-src", []],
["font-src", []],
[
"img-src",
[
"favicon.png",
// TODO: These should be dynamically added (from the manifest), but it's not available at this point
"icon_512x512.e3175643e8fe0d95175a493da5201480.png",
"icon_384x384.971e45062e4d601a3014dc16ee3ed27b.png",
"icon_256x256.9a47fba2857d94939047064f37cd075f.png",
"icon_192x192.8dfb7236c7e6b6591567173b18eaa144.png",
"icon_128x128.f620784d1682c9fbb033d3b018e7d998.png",
"icon_96x96.eda9f98be1c35dabab77f9d2ab7be538.png",
],
],
// TODO: This should to be dynamically added, but it's not available at this point
["manifest-src", ["manifest.623e2268f17398ec7f19225e281e4056.json"]],
]);
// Add the root PWA URL of webpack-dev-server to script-src when building locally, otherwise server hot reloading won't work
if (isBuildingLocally) {
builtFilesForCsp.get("script-src").push("");
}
const assets = compilation.getAssets();
for (const asset of assets) {
const fileExtension = asset.name.split(".").pop();
if (!fileExtensionsToCspRule.has(fileExtension)) {
throw new Error(`No CSP rule found for ".${fileExtension}"! (${asset.name})`);
}
const cspRule = fileExtensionsToCspRule.get(fileExtension);
if (!builtFilesForCsp.has(cspRule)) {
throw new Error(`No CSP rule found for "${cspRule}"! (${fileExtension})`);
}
builtFilesForCsp.get(cspRule).push(asset.name);
}
// Manually add the files in for the CSP meta tag
for (const cspRule of builtFilesForCsp.keys()) {
// Sort all files first
const files = builtFilesForCsp.get(cspRule);
files.sort();
data.html = data.html.replace(
`[REPLACE_${cspRule.replace("-src", "").toUpperCase()}]`,
`${files.map((file) => `${pwaUrl}/${file}`).join(" ")}`
);
}
// Add the websocket URL + PWA URL of webpack-dev-server to connect-src when building locally, or nothing otherwise
let connectReplacement = isBuildingLocally
? `ws://localhost:${process.env.PL_PWA_PORT || 8080}/ws ${pwaUrl}`
: "";
data.html = data.html.replace("[REPLACE_CONNECT]", connectReplacement);
callback(null, data);
}
);
return true;
});
},
},
new HtmlWebpackPlugin({
title: name,
template: resolve(__dirname, "src/index.html"),
meta: {
"Content-Security-Policy": {
"http-equiv": "Content-Security-Policy",
content: `default-src 'self' ${serverUrl} https://api.pwnedpasswords.com blob:; style-src 'self' 'unsafe-inline'; object-src 'self' blob:; frame-src 'self'; img-src 'self' blob: data: https:;`,
content: `default-src 'none'; base-uri 'none'; script-src blob: [REPLACE_SCRIPT]; connect-src ${serverUrl} https://api.pwnedpasswords.com [REPLACE_CONNECT]; style-src 'unsafe-inline'; font-src [REPLACE_FONT]; object-src blob:; frame-src 'none'; img-src [REPLACE_IMG] blob: data: https://icons.duckduckgo.com; manifest-src [REPLACE_MANIFEST]; worker-src ${pwaUrl}/sw.js;`,
},
},
}),

View File

@ -22,5 +22,6 @@
"esModuleInterop": true,
"allowJs": true,
"useUnknownInCatchVariables": false
}
},
"exclude": ["docs"]
}