Skip to content

Demo site for webassembly#376

Open
Sébastien Duquette (sduquette-devolutions) wants to merge 8 commits intomasterfrom
wasm-demo
Open

Demo site for webassembly#376
Sébastien Duquette (sduquette-devolutions) wants to merge 8 commits intomasterfrom
wasm-demo

Conversation

@sduquette-devolutions

No description provided.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a standalone Angular demo application under wrappers/wasm/devolutions-crypto-wasm-demo to showcase functionality from @devolutions/devolutions-crypto-web (WASM), with pages for encryption, secret sharing, password hashing, utilities, and asymmetric operations.

Changes:

  • Introduces a new Angular app scaffold (config files, build/serve setup, Tailwind/PostCSS, global styles, assets).
  • Adds an EncryptionService wrapper that lazy-loads/awaits the WASM module and exposes crypto helpers via an “inner” module.
  • Implements multiple standalone feature components + routing for the demo UI.

Reviewed changes

Copilot reviewed 29 out of 32 changed files in this pull request and generated 21 comments.

Show a summary per file
File Description
wrappers/wasm/devolutions-crypto-wasm-demo/tsconfig.json Base TS/Angular compiler configuration for the demo app.
wrappers/wasm/devolutions-crypto-wasm-demo/tsconfig.app.json App-specific TS configuration and entrypoint inclusion.
wrappers/wasm/devolutions-crypto-wasm-demo/angular.json Angular CLI project configuration (build, serve, assets, styles).
wrappers/wasm/devolutions-crypto-wasm-demo/package.json Demo app dependencies/scripts (Angular, Tailwind, crypto WASM lib).
wrappers/wasm/devolutions-crypto-wasm-demo/postcss.config.js PostCSS config enabling Tailwind pipeline.
wrappers/wasm/devolutions-crypto-wasm-demo/README.md Basic Angular CLI-generated README for the demo app.
wrappers/wasm/devolutions-crypto-wasm-demo/.gitignore Ignores Angular/Node build outputs and tooling artifacts.
wrappers/wasm/devolutions-crypto-wasm-demo/.editorconfig Formatting conventions for the demo app files.
wrappers/wasm/devolutions-crypto-wasm-demo/public/favicon.ico Demo app favicon asset.
wrappers/wasm/devolutions-crypto-wasm-demo/src/index.html Demo app HTML host document.
wrappers/wasm/devolutions-crypto-wasm-demo/src/main.ts Bootstraps the standalone Angular application.
wrappers/wasm/devolutions-crypto-wasm-demo/src/styles.css Global styling + Tailwind import and layout styles.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/app.config.ts App-level providers (router, zone change detection).
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/app.routes.ts Route definitions for the demo pages.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/app.component.ts Root shell component for sidebar/navigation.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/app.component.html Root layout with sidebar and overlay + router outlet.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/app.component.css Root component stylesheet (currently empty).
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/shared/shared.component.ts DOM helpers to open/close sidebar/overlay.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/service/encryption.service.ts Lazy-load service to await WASM readiness.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/service/encryption.inner.service.ts Thin wrapper around @devolutions/devolutions-crypto-web + WASM init.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/encryption/encryption.component.ts Symmetric encrypt/decrypt demo logic.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/encryption/encryption.component.html Symmetric encrypt/decrypt UI.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/secret-sharing/secret-sharing.component.ts Shamir secret sharing demo logic (generate/join).
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/secret-sharing/secret-sharing.component.html Shamir secret sharing UI.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/password/password.component.ts Password hashing + verify demo logic.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/password/password.component.html Password hashing + verify UI.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/utilities/utilities.component.ts Base64 encode/decode + key generation + PBKDF2 derive demo logic.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/utilities/utilities.component.html Utilities UI.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/asymmetric/asymmetric.component.ts Argon2 params + keypair + key exchange + asymmetric encrypt/decrypt demo logic.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/asymmetric/asymmetric.component.html Asymmetric crypto UI.
wrappers/wasm/devolutions-crypto-wasm-demo/src/app/model/encryption.ts Adds an Encryption model class (currently unused).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +58 to +65
const nbShares: string = this.generateSharesForm.value.nbShares;
const threshold: string = this.generateSharesForm.value.threshold;
const secretLengthString: string = this.generateSharesForm.value.secretLength;
if (nbShares === null || nbShares === '' || threshold === null || threshold === '') { return; }

const secretLength: number | undefined = (secretLengthString === null || secretLengthString === '') ? undefined : Number(secretLengthString);
const generatedKeys: Uint8Array[] = service.generateSharedKey(Number(nbShares), Number(threshold), secretLength);

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Number(...) is used to parse secretLength, nbShares, and threshold without checking for NaN or validating ranges. Non-numeric input (or invalid values like threshold > shares) will flow into generateSharedKey(...) and may throw or produce incorrect output. Add validation (e.g., parseInt + isNaN checks + range checks) before calling the WASM API.

Suggested change
const nbShares: string = this.generateSharesForm.value.nbShares;
const threshold: string = this.generateSharesForm.value.threshold;
const secretLengthString: string = this.generateSharesForm.value.secretLength;
if (nbShares === null || nbShares === '' || threshold === null || threshold === '') { return; }
const secretLength: number | undefined = (secretLengthString === null || secretLengthString === '') ? undefined : Number(secretLengthString);
const generatedKeys: Uint8Array[] = service.generateSharedKey(Number(nbShares), Number(threshold), secretLength);
const nbSharesRaw: string = this.generateSharesForm.value.nbShares;
const thresholdRaw: string = this.generateSharesForm.value.threshold;
const secretLengthString: string = this.generateSharesForm.value.secretLength;
if (nbSharesRaw === null || nbSharesRaw === '' || thresholdRaw === null || thresholdRaw === '') { return; }
const nbSharesParsed: number = parseInt(nbSharesRaw, 10);
const thresholdParsed: number = parseInt(thresholdRaw, 10);
if (Number.isNaN(nbSharesParsed) || Number.isNaN(thresholdParsed)) { return; }
if (nbSharesParsed <= 0 || thresholdParsed <= 0) { return; }
if (thresholdParsed > nbSharesParsed) { return; }
let secretLength: number | undefined;
if (secretLengthString !== null && secretLengthString !== '') {
const secretLengthParsed: number = parseInt(secretLengthString, 10);
if (Number.isNaN(secretLengthParsed) || secretLengthParsed <= 0) { return; }
secretLength = secretLengthParsed;
} else {
secretLength = undefined;
}
const generatedKeys: Uint8Array[] = service.generateSharedKey(nbSharesParsed, thresholdParsed, secretLength);

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +24
generatedKeysBase64: string[] = [];
joinnedSharesToShow: string[] = [];
joinnedShares: Uint8Array[] = [];
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

joinnedSharesToShow / joinnedShares appear to be misspellings of “joined…”. Since these names are used in the component and template, correcting them now will improve readability and avoid spreading the typo.

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +96
parameters.iterations = Number(argon2Iterations);
}
if (argon2Lanes) {
parameters.lanes = Number(argon2Lanes);
}
if (argon2Length) {
parameters.length = Number(argon2Length);
}
if (argon2Memory) {
parameters.memory = Number(argon2Memory);
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argon2 parameter fields are converted with Number(...) without validation. If the user enters non-numeric input, these properties become NaN, and encoding parameters.bytes may yield invalid parameters. Validate parsed values (integer/positive/range) before setting them.

Suggested change
parameters.iterations = Number(argon2Iterations);
}
if (argon2Lanes) {
parameters.lanes = Number(argon2Lanes);
}
if (argon2Length) {
parameters.length = Number(argon2Length);
}
if (argon2Memory) {
parameters.memory = Number(argon2Memory);
const iterationsValue = Number(argon2Iterations);
if (Number.isFinite(iterationsValue) && Number.isInteger(iterationsValue) && iterationsValue > 0) {
parameters.iterations = iterationsValue;
}
}
if (argon2Lanes) {
const lanesValue = Number(argon2Lanes);
if (Number.isFinite(lanesValue) && Number.isInteger(lanesValue) && lanesValue > 0) {
parameters.lanes = lanesValue;
}
}
if (argon2Length) {
const lengthValue = Number(argon2Length);
if (Number.isFinite(lengthValue) && Number.isInteger(lengthValue) && lengthValue > 0) {
parameters.length = lengthValue;
}
}
if (argon2Memory) {
const memoryValue = Number(argon2Memory);
if (Number.isFinite(memoryValue) && Number.isInteger(memoryValue) && memoryValue > 0) {
parameters.memory = memoryValue;
}

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +8
(document.getElementById('mySidebar') as HTMLElement).style.display = 'flex';
(document.getElementById('myOverlay') as HTMLElement).style.display = 'block';
}

export function w3_close() {
(document.getElementById('mySidebar') as HTMLElement).style.display = 'none';
(document.getElementById('myOverlay') as HTMLElement).style.display = 'none';
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

w3_close() has the same unchecked getElementById(...) as HTMLElement dereference as w3_open(), which can throw if the element isn’t present or IDs aren’t unique. Add a null check (or switch to Angular refs/Renderer2) before mutating .style.

Suggested change
(document.getElementById('mySidebar') as HTMLElement).style.display = 'flex';
(document.getElementById('myOverlay') as HTMLElement).style.display = 'block';
}
export function w3_close() {
(document.getElementById('mySidebar') as HTMLElement).style.display = 'none';
(document.getElementById('myOverlay') as HTMLElement).style.display = 'none';
const sidebar = document.getElementById('mySidebar');
if (sidebar instanceof HTMLElement) {
sidebar.style.display = 'flex';
}
const overlay = document.getElementById('myOverlay');
if (overlay instanceof HTMLElement) {
overlay.style.display = 'block';
}
}
export function w3_close() {
const sidebar = document.getElementById('mySidebar');
if (sidebar instanceof HTMLElement) {
sidebar.style.display = 'none';
}
const overlay = document.getElementById('myOverlay');
if (overlay instanceof HTMLElement) {
overlay.style.display = 'none';
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants