Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add meta code verify #311

Merged
merged 37 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a0ab233
first commit
spiritbroski Mar 9, 2023
41fde68
Merge branch 'main' into meta-code-verify
spiritbroski Mar 27, 2023
5d311ab
done and need review
spiritbroski Mar 28, 2023
24b3969
add all of em
spiritbroski Mar 28, 2023
3c92c59
fix lint
spiritbroski Mar 28, 2023
ed25046
adding origin to ipfs, also check whether origin is the same
spiritbroski Apr 2, 2023
f008c94
fix lint
spiritbroski Apr 2, 2023
2fc75cf
remove yarn.lock and put test inside .github root folder
spiritbroski Apr 4, 2023
291a13d
Merge branch 'develop' into meta-code-verify
spiritbroski Apr 4, 2023
45f9736
add README.md and delete unnecessary files
spiritbroski Apr 5, 2023
45c9746
Merge branch 'develop' into meta-code-verify
spiritbroski Apr 5, 2023
15f2cc0
rename build to built
spiritbroski Apr 6, 2023
f206b22
fix the docs
spiritbroski Apr 11, 2023
8b9125f
refactor(i18n): add i18nAllowlist message
spiritbroski Apr 18, 2023
7347ef0
fix(manifest): update manifest permissions
spiritbroski Apr 18, 2023
82b072d
feat(manifest): add new permissions and host permissions
spiritbroski Apr 18, 2023
58fd3e8
style(popup): add allowlist section to menu
spiritbroski Apr 18, 2023
3d97dd0
feat(background): add support for validating meta company manifests
spiritbroski Apr 18, 2023
958f449
fix(config): change KVSTORE origin to localhost
spiritbroski Apr 18, 2023
33ec312
add allowlist done
spiritbroski Apr 19, 2023
b2d14b3
Merge branch 'meta-code-verify' of github.com:spiritbroski/human-prot…
spiritbroski Apr 19, 2023
ceeb02b
Merge branch 'develop' into meta-code-verify
spiritbroski Apr 19, 2023
c2fa0f3
Update README.md
spiritbroski Apr 19, 2023
869754f
Update README.md
spiritbroski Apr 19, 2023
f1b54a3
change ipfs_cid to version
spiritbroski Apr 19, 2023
04e97c1
fix extension always validate even though its risk
spiritbroski Apr 19, 2023
30d12fb
Update README.md
spiritbroski Apr 19, 2023
0299156
change jest to vitest, change js to ts
spiritbroski Apr 20, 2023
420dafe
Merge branch 'meta-code-verify' of github.com:spiritbroski/human-prot…
spiritbroski Apr 20, 2023
036890e
fix test
spiritbroski Apr 21, 2023
8b4cb6f
build: update package.json for meta-code-verify
spiritbroski Apr 21, 2023
e575714
Update ci-test-meta-code-verify.yml
spiritbroski Apr 21, 2023
d8d2b42
Update README.md
spiritbroski Apr 22, 2023
5fc5ef3
Update README.md
spiritbroski Apr 22, 2023
920abfe
adding generateMerkleTree.ts test
spiritbroski Apr 22, 2023
49816a2
fix lint
spiritbroski Apr 23, 2023
4fbf7fd
Merge branch 'develop' into meta-code-verify
spiritbroski Apr 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/ci-test-meta-code-verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: meta-code-verify CI

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [18.x]

steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: yarn install --frozen-lockfile
- run: yarn makeBundle
- run: yarn test
1 change: 1 addition & 0 deletions packages/apps/escrow-dashboard/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script id="binary-transparency-manifest" type="application/json"></script>
</body>
</html>
5 changes: 5 additions & 0 deletions packages/apps/escrow-dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,15 @@
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/crypto-js": "^4.1.1",
"@types/glob": "^8.1.0",
"@types/numeral": "^2.0.2",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9",
"@types/react-test-renderer": "^18.0.0",
"@vitejs/plugin-react": "^3.1.0",
"crypto-js": "^4.1.1",
"dotenv": "^16.0.3",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.26.0",
Expand All @@ -49,6 +53,7 @@
"happy-dom": "^8.2.6",
"identity-obj-proxy": "^3.0.0",
"jsdom": "^21.1.0",
"merkletreejs": "^0.3.9",
"resize-observer-polyfill": "^1.5.1",
"vite": "^4.1.4",
"vite-plugin-node-polyfills": "^0.7.0",
Expand Down
47 changes: 47 additions & 0 deletions packages/apps/escrow-dashboard/scripts/generateMerkleTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as fs from 'fs';
import * as path from 'path';
import { SHA256 } from 'crypto-js';
import * as glob from 'glob';
import { MerkleTree } from 'merkletreejs';
import { NFTStorage } from 'nft.storage';

export default async function generateMerkleTree(
origin: string,
token: string
): Promise<string> {
const buildPath = path.join(__dirname, '../dist/assets');
const allFiles = glob.sync('**/*.js', { cwd: buildPath });
const NFT_STORAGE_CLIENT = new NFTStorage({
token,
});
const fileHashes = allFiles.map((file) => {
const filePath = path.join(buildPath, file);
const fileContent = fs.readFileSync(filePath, 'utf-8');
return SHA256(fileContent).toString();
});

const merkleTree = new MerkleTree(fileHashes, SHA256);
const merkleRoot = '0x' + merkleTree.getRoot().toString('hex');

// Add the '0x' prefix to each leaf
const leaves = merkleTree
.getLeaves()
.map((leaf) => '0x' + leaf.toString('hex'));

const someData = new Blob([
JSON.stringify({
origin,
root_hash: merkleRoot,
published_date: Date.now(),
}) as string,
]);
const cid = await NFT_STORAGE_CLIENT.storeBlob(someData);

const merkleTreeJson = JSON.stringify({
ipfs_cid: cid,
root: merkleRoot,
leaves: leaves,
});

return merkleTreeJson;
}
75 changes: 50 additions & 25 deletions packages/apps/escrow-dashboard/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,60 @@
/// <reference types="vitest" />
/// <reference types="vite/client" />

import * as fs from 'fs';
import path from 'path';
import react from '@vitejs/plugin-react';
import dotenv from 'dotenv';
import { defineConfig } from 'vite';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
import generateMerkleTree from './scripts/generateMerkleTree';

dotenv.config();
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
react({ fastRefresh: false }),
nodePolyfills({
// Whether to polyfill `node:` protocol imports.
protocolImports: true,
}),
],
worker: {
plugins: [react()],
},
resolve: {
alias: [{ find: 'src', replacement: path.resolve(__dirname, 'src') }],
},
test: {
globals: true,
environment: 'happy-dom',
setupFiles: './tests/setup.ts',
coverage: {
reporter: ['text', 'json', 'html'],
export default defineConfig(({ mode }) => {
return {
plugins: [
react({ fastRefresh: false }),
nodePolyfills({
// Whether to polyfill `node:` protocol imports.
protocolImports: true,
}),
{
name: 'generate-merkle-tree',
apply: 'build',
async writeBundle() {
const merkleTreeJson = await generateMerkleTree(
mode === 'development'
? 'localhost'
: 'dashboard.humanprotocol.org',
process.env.VITE_APP_NFT_STORAGE_API as string
);

const indexPath = path.resolve(__dirname, './dist/index.html');
const indexContent = fs.readFileSync(indexPath, 'utf-8');
const newIndexContent = indexContent.replace(
'<script id="binary-transparency-manifest" type="application/json"></script>',
`<script id="binary-transparency-manifest" type="application/json">${merkleTreeJson}</script>`
);
fs.writeFileSync(indexPath, newIndexContent);
},
},
],
worker: {
plugins: [react()],
},
resolve: {
alias: [{ find: 'src', replacement: path.resolve(__dirname, 'src') }],
},
test: {
globals: true,
environment: 'happy-dom',
setupFiles: './tests/setup.ts',
coverage: {
reporter: ['text', 'json', 'html'],
},
},
server: {
port: 3002,
},
},
server: {
port: 3002,
},
};
});
21 changes: 21 additions & 0 deletions packages/apps/meta-code-verify/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"root": true,
"env": {
"browser": true,
"es2021": true,
"jest": true,
"webextensions": true
},
"parserOptions": { "project": ["./tsconfig.json"] },
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-unused-vars": ["error", {"argsIgnorePattern": "^_"}],
"@typescript-eslint/no-empty-function": 0,
"@typescript-eslint/no-extra-semi": 0
}
}
5 changes: 5 additions & 0 deletions packages/apps/meta-code-verify/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist/chrome
dist/edge
dist/firefox
node_modules
.env
12 changes: 12 additions & 0 deletions packages/apps/meta-code-verify/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "avoid",
"proseWrap": "preserve"
}
67 changes: 67 additions & 0 deletions packages/apps/meta-code-verify/README.md
portuu3 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Video Demo

[Video Demo](https://www.youtube.com/watch?v=BZfnLPGep-4)

# Description

This project is a modified version of [meta-code-verify](https://github.com/facebookincubator/meta-code-verify) by Facebook. In simple terms, it's a web extension for checking if the JavaScript hasn't been tampered with by creating a Merkle tree both on the client and server side. You can read more about this concept on the [Mozilla Wiki](https://wiki.mozilla.org/Security/Binary_Transparency). The code pushed to the repository includes a [script](https://github.com/spiritbroski/human-protocol/blob/24b39697a51096c9f982b00b44a469b0c11470de/packages/apps/escrow-dashboard/scripts/generateMerkleTree.ts) to generate a Merkle tree in Vite, and then push the root of the Merkle tree to IPFS. The design is inspired by the WhatsApp binary transparency manifest:

![WhatsApp Binary Transparency Manifest](https://user-images.githubusercontent.com/62529025/228214669-6cc7446d-e2b1-455f-af94-ebd8f60aba80.png)

Here's what it looks like in our apps:

![App Screenshot](https://user-images.githubusercontent.com/62529025/228215108-8891f6dc-23f3-4fa8-9188-c780707c50c0.png)

The main difference is the removal of `version` and `hash_function`, replaced by `ipfs_cid`, which can later be used to verify the Merkle tree. While WhatsApp pushes their Merkle root to Cloudflare, our implementation is more resilient as it's decentralized in IPFS, in contrast to the centralized server solution used by Cloudflare. The following is a brief description of the project and how to use it.

# How to Use

As this is a web extension, you'll need to have either a Chrome-based browser or Firefox. In this demo, we use Brave browser. First, navigate to `packages/apps/meta-code-verify` and run this script:

```bash
$ yarn
$ yarn build-local-dev
```

Then, go to your browser and open this URL: `brave://extensions/.` Turn on developer mode if you haven't:

![Developer mode](https://user-images.githubusercontent.com/62529025/228216854-1e85b3c3-3f13-441f-82c3-ed188dffeed6.png)

Click "Load Unpacked":

![Load unpacked](https://user-images.githubusercontent.com/62529025/228217073-da947a33-e591-48a4-b283-29b258c5128c.png)

Navigate to the `dist/chrome` folder of meta-code-verify, then click "Select Folder":

![Navigate](https://user-images.githubusercontent.com/62529025/228217002-c866ff59-2f32-4c7d-9596-af88e98e0e2b.png)

If successful, it will show something like this:

![Success](https://user-images.githubusercontent.com/62529025/228217415-034622c6-0cf6-46c2-9d58-237ca72d8bf5.png)

Now, go to `packages/apps/escrow-dashboard` and run these commands:

```
$ yarn
$ yarn build --mode development
```

Wait until it finishes building, then run:

```
$ yarn start-prod
```

Go to your browser and navigate to `http://localhost:3000` If you click on the web extension icon, you'll see a green checkmark, indicating that our code is not tampered with:

![Not tampered](https://user-images.githubusercontent.com/62529025/228218083-ea324fe9-fb45-46be-80dc-3ed6a712d983.png)

To test if our code is getting tampered with, first, stop the `yarn start-prod` command (use CTRL+C on Linux). Then, go to `index.html` in the `packages/apps/escrow-dashboard` and add `<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>`:

![Script added](https://user-images.githubusercontent.com/62529025/228218787-69c76cbe-fef1-42eb-b917-5fc5c2959048.png)

Run `yarn build --mode development` again, followed by `yarn start-prod`. When you go to `http://localhost:3000` again, you'll see a red exclamation mark:

![Red exclamation](https://user-images.githubusercontent.com/62529025/228222259-d144fd17-0f7d-4a2b-93ff-caf57ae31ced.png)

This indicates that one or more scripts are not in the Merkle tree. If you download it, you'll get a list of all JavaScript files and their source code in gzip files, so you can check it yourself.
Loading