diff --git a/.github/workflows/build-wasm.yml b/.github/workflows/build-wasm.yml new file mode 100644 index 000000000..0bc29b4e0 --- /dev/null +++ b/.github/workflows/build-wasm.yml @@ -0,0 +1,58 @@ +--- +name: Build @bitwarden/sdk-wasm + +on: + pull_request: + push: + branches: + - "main" + - "rc" + - "hotfix-rc" + workflow_dispatch: + +defaults: + run: + shell: bash + working-directory: crates/bitwarden-wasm + +jobs: + build: + name: Building @bitwarden/sdk-wasm + runs-on: ubuntu-22.04 + + steps: + - name: Checkout repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: 18 + cache: "npm" + + - name: Install dependencies + run: npm i -g binaryen + + - name: Install rust + uses: dtolnay/rust-toolchain@be73d7920c329f220ce78e0234b8f96b7ae60248 # stable + with: + toolchain: stable + targets: wasm32-unknown-unknown + + - name: Cache cargo registry + uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + with: + key: wasm-cargo-cache + + - name: Install wasm-bindgen-cli + run: cargo install wasm-bindgen-cli + + - name: Build + run: ./build.sh -r + + - name: Upload artifact + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: sdk-bitwarden-wasm + path: ${{ github.workspace }}/languages/js/wasm/* + if-no-files-found: error diff --git a/.github/workflows/release-wasm.yml b/.github/workflows/release-wasm.yml new file mode 100644 index 000000000..c4946a0e1 --- /dev/null +++ b/.github/workflows/release-wasm.yml @@ -0,0 +1,132 @@ +--- +name: Release @bitwarden/sdk-wasm +run-name: Release @bitwarden/sdk-wasm ${{ inputs.release_type }} + +on: + workflow_dispatch: + inputs: + release_type: + description: "Release Options" + required: true + default: "Release" + type: choice + options: + - Release + - Dry Run + npm_publish: + description: "Publish to NPM registry" + required: true + default: true + type: boolean + +defaults: + run: + shell: bash + working-directory: languages/js/wasm + +jobs: + setup: + name: Setup + runs-on: ubuntu-22.04 + outputs: + release-version: ${{ steps.version.outputs.version }} + steps: + - name: Checkout repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Branch check + if: ${{ github.event.inputs.release_type != 'Dry Run' }} + run: | + if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then + echo "===================================" + echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches" + echo "===================================" + exit 1 + fi + + - name: Check Release Version + id: version + uses: bitwarden/gh-actions/release-version-check@main + with: + release-type: ${{ github.event.inputs.release_type }} + project-type: ts + file: languages/js/wasm/package.json + monorepo: false + + - name: Create GitHub deployment + if: ${{ github.event.inputs.release_type != 'Dry Run' }} + uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7 + id: deployment + with: + token: "${{ secrets.GITHUB_TOKEN }}" + initial-status: "in_progress" + environment: "Bitwarden SDK WASM - Production" + description: "Deployment ${{ steps.version.outputs.version }} from branch ${{ github.ref_name }}" + task: release + + - name: Update deployment status to Success + if: ${{ github.event.inputs.release_type != 'Dry Run' && success() }} + uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + with: + token: "${{ secrets.GITHUB_TOKEN }}" + state: "success" + deployment-id: ${{ steps.deployment.outputs.deployment_id }} + + - name: Update deployment status to Failure + if: ${{ github.event.inputs.release_type != 'Dry Run' && failure() }} + uses: chrnorm/deployment-status@2afb7d27101260f4a764219439564d954d10b5b0 # v2.0.1 + with: + token: "${{ secrets.GITHUB_TOKEN }}" + state: "failure" + deployment-id: ${{ steps.deployment.outputs.deployment_id }} + + npm: + name: Publish NPM + runs-on: ubuntu-22.04 + needs: setup + if: inputs.npm_publish + env: + _PKG_VERSION: ${{ needs.setup.outputs.release-version }} + steps: + - name: Checkout repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Setup Node + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + with: + node-version: 18 + cache: "npm" + + - name: Login to Azure + uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + with: + creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + + - name: Retrieve secrets + id: retrieve-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: "bitwarden-ci" + secrets: "npm-api-key" + + - name: Download artifacts + uses: bitwarden/gh-actions/download-artifacts@main + with: + workflow: build-wasm.yml + path: ${{ github.workspace }}/languages/js/wasm + workflow_conclusion: success + branch: ${{ github.event.inputs.release_type == 'Dry Run' && 'main' || github.ref_name }} + + - name: Setup NPM + run: | + echo 'registry="https://registry.npmjs.org/"' > ./.npmrc + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ./.npmrc + + echo 'registry="https://registry.npmjs.org/"' > ~/.npmrc + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc + env: + NPM_TOKEN: ${{ steps.retrieve-secrets.outputs.npm-api-key }} + + - name: Publish NPM + if: ${{ github.event.inputs.release_type != 'Dry Run' }} + run: npm publish --access public --registry=https://registry.npmjs.org/ --userconfig=./.npmrc diff --git a/Cargo.lock b/Cargo.lock index a00d91bd8..bda3a9c4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -522,6 +522,7 @@ dependencies = [ name = "bitwarden-wasm" version = "0.1.0" dependencies = [ + "argon2", "bitwarden-json", "console_error_panic_hook", "console_log", diff --git a/crates/bitwarden-wasm/Cargo.toml b/crates/bitwarden-wasm/Cargo.toml index ff4cf13c3..a4ba8b6ae 100644 --- a/crates/bitwarden-wasm/Cargo.toml +++ b/crates/bitwarden-wasm/Cargo.toml @@ -15,6 +15,10 @@ keywords.workspace = true crate-type = ["cdylib"] [dependencies] +argon2 = { version = ">=0.5.0, <0.6", features = [ + "alloc", + "zeroize", +], default-features = false } bitwarden-json = { path = "../bitwarden-json", features = [ "secrets", "internal", diff --git a/crates/bitwarden-wasm/src/client.rs b/crates/bitwarden-wasm/src/client.rs index 542759731..bca8c2383 100644 --- a/crates/bitwarden-wasm/src/client.rs +++ b/crates/bitwarden-wasm/src/client.rs @@ -1,6 +1,7 @@ extern crate console_error_panic_hook; use std::rc::Rc; +use argon2::{Algorithm, Argon2, Params, Version}; use bitwarden_json::client::Client as JsonClient; use js_sys::Promise; use log::Level; @@ -54,3 +55,27 @@ impl BitwardenClient { }) } } + +#[wasm_bindgen] +pub fn argon2( + password: &[u8], + salt: &[u8], + iterations: u32, + memory: u32, + parallelism: u32, +) -> Result, JsError> { + let argon = Argon2::new( + Algorithm::Argon2id, + Version::V0x13, + Params::new( + memory * 1024, // Convert MiB to KiB + iterations, + parallelism, + Some(32), + )?, + ); + + let mut hash = [0u8; 32]; + argon.hash_password_into(password, salt, &mut hash)?; + Ok(hash.to_vec()) +} diff --git a/languages/js/wasm/package.json b/languages/js/wasm/package.json index 26379c9a6..eadbb5fb3 100644 --- a/languages/js/wasm/package.json +++ b/languages/js/wasm/package.json @@ -4,17 +4,20 @@ "files": [ "bitwarden_wasm_bg.js", "bitwarden_wasm_bg.wasm", + "bitwarden_wasm_bg.wasm.d.ts", + "bitwarden_wasm_bg.wasm.js", "bitwarden_wasm.d.ts", "bitwarden_wasm.js", "index.js", - "node/bitwarden_wasm_bg.wasm.d.ts", "node/bitwarden_wasm_bg.wasm", + "node/bitwarden_wasm_bg.wasm.d.ts", "node/bitwarden_wasm.d.ts", "node/bitwarden_wasm.js" ], "main": "node/bitwarden_wasm.js", "module": "index.js", "types": "bitwarden_wasm.d.ts", + "scripts": {}, "sideEffects": [ "./bitwarden_wasm.js", "./snippets/*"