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

feat: wrap payload in envelope #23

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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: 29 additions & 1 deletion packages/core/src/lavadome.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,49 @@ import {
createElement,
appendChild,
textContentSet,
WeakMap, create, set, get
} from './native.mjs';
import {distraction, unselectable} from './element.mjs';
import {getShadow} from './shadow.mjs';


// there's no code running earlier
const STORE = new WeakMap();

export const envelope = (secret) => {
const en = create(null);
set(STORE, en, secret);
return en;
};


export function LavaDome(host, opts) {
opts = options(opts);

// make exported API tamper-proof
defineProperties(this, {text: {value: text}});
defineProperties(this, {
text: {value: text, writable: false, configurable: false},
envelope: {value: envelope, writable: false, configurable: false},
});

// child of the shadow, where the secret is set, must be unselectable
const child = unselectable();
const shadow = getShadow(host, opts);
appendChild(shadow, child);

function envelope(anEnvelope) {
if (typeof anEnvelope !== 'object') {
throw new Error(
`LavaDome: first argument must be an object, instead got ${stringify(anEnvelope)}`);
}
const secret = get(STORE, anEnvelope);
if (secret === undefined) {
throw new Error(
`LavaDome: first argument must be an envelope`);
}
text(secret);
}

function text(text) {
if (typeof text !== 'string') {
throw new Error(
Expand Down
4 changes: 2 additions & 2 deletions packages/react/demo/App.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { LavaDome as LavaDomeReact } from '../src/index';
import { LavaDome as LavaDomeReact, envelope } from '../src/index';

const unsafeOpenModeShadow = location.href.includes('unsafeOpenModeShadow');

Expand All @@ -17,7 +17,7 @@ export default function App() {
<p id="PRIVATE">
<LavaDomeReact
unsafeOpenModeShadow={unsafeOpenModeShadow}
text={'SECRET_CONTENT_ONLY_ACCESSIBLE_TO_LAVADOME'}
envelope={envelope('SECRET_CONTENT_ONLY_ACCESSIBLE_TO_LAVADOME')}
/>
</p>
</div>
Expand Down
4 changes: 3 additions & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
"swc-loader": "^0.2.3",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "4.15.1"
"webpack-dev-server": "4.15.1",
"react": "^16.12.0",
"react-dom": "^16.12.0"
Copy link
Member Author

Choose a reason for hiding this comment

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

they didn't get installed by default. for the build to work we need to have these as dev deps

},
"dependencies": {
"@lavamoat/lavadome-core": "^0.0.10"
Expand Down
12 changes: 7 additions & 5 deletions packages/react/src/index.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import React, { useEffect, useRef } from 'react'
import { LavaDome as LavaDomeCore } from "@lavamoat/lavadome-core"
export { envelope } from "@lavamoat/lavadome-core"

export const LavaDome = ({ text, unsafeOpenModeShadow }) => {
export const LavaDome = ({ envelope, unsafeOpenModeShadow }) => {
const hostRef = useRef(null);
return (
<span ref={hostRef}>
<LavaDomeShadow
text={text} hostRef={hostRef}
envelope={envelope} hostRef={hostRef}
unsafeOpenModeShadow={unsafeOpenModeShadow}
/>
</span>
)
};

function LavaDomeShadow({ hostRef, text, unsafeOpenModeShadow }) {
function LavaDomeShadow({ hostRef, envelope, unsafeOpenModeShadow }) {
const lavadome = useRef(null);

useEffect(() => {
Expand All @@ -24,8 +25,9 @@ function LavaDomeShadow({ hostRef, text, unsafeOpenModeShadow }) {
}, [])

useEffect(() => {
lavadome.current.text(text);
}, [text]);
const payload = STORE.get(envelope);
lavadome.current.envelope(payload);
}, [envelope]);
Comment on lines +28 to +30
Copy link
Member Author

Choose a reason for hiding this comment

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

Suggested change
const payload = STORE.get(envelope);
lavadome.current.envelope(payload);
}, [envelope]);
lavadome.current.envelope(envelope);
}, [envelope]);

Sorry, missed this one when refactoring.


return <></>
}
21 changes: 21 additions & 0 deletions packages/react/test/basic.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,25 @@ describe('test javascript mode', async function () {
expect(result.includes('TO BE REPLACED')).toBeFalsy();
expect(result.includes('SECRET_CONTENT_ONLY_ACCESSIBLE_TO_LAVADOME')).toBeFalsy();
});
it('steal secret from react metadata on DOM nodes', async function () {
const result = await browser.executeAsync(function(done) {
const hostref = document.querySelector("#PRIVATE>span");
const cache = new Set();
const result = JSON.stringify(
hostref[
Object.getOwnPropertyNames(hostref).find((a) => a.includes("reactInternal"))
].child,
(key, value) => {
if (typeof value === "object" && value !== null) {
if (cache.has(value)) return;
cache.add(value);
}
return value;
}
);
// specifically in the props / memoizedProps fields
done(result)
});
expect(result.includes('SECRET_CONTENT_ONLY_ACCESSIBLE_TO_LAVADOME')).toBeFalsy();
});
});