Conversation
7958a69 to
fa4643f
Compare
|
|
||
| function text(text) { | ||
| if (typeof text !== 'string') { | ||
| let secret = ''; |
There was a problem hiding this comment.
It doesn't feel great to have the secret hang out in memory in this long-lived scope... Not that I have a proposal on how it could be achieved differently, though...
There was a problem hiding this comment.
I see your point, but essentially, it's only natural that in order to provide service where the input is somehow manipulated we must have access to it
| defineProperties(this, {text: {value: text}}); | ||
| defineProperties(this, { | ||
| text: {value: text}, | ||
| copy: {value: copy}, |
There was a problem hiding this comment.
Re https://github.com/LavaMoat/LavaDome/pull/50/files#r1782176796
Could setting the value of copy (including its declaration and instantiation) be moved to the inner scope of text? If so, maybe the need to move secret out of scope is no longer here?
Or would that conflict with the "make exported API tamper-proof" part? If so I think I'm still leaning towards that as the lesser bad. WDYT?
There was a problem hiding this comment.
How would we export copy if it's inside text?
There was a problem hiding this comment.
If we assign it inside the handler of text, is there a need to?
There was a problem hiding this comment.
AFAIU, if you move the copy function into the text function, you closure the secret within the text scope instead of the LavaDome scope, which doesn't solve the problem, just shifts it elsewhere - the secret still must be scoped somewhere
There was a problem hiding this comment.
The secret is already part of the text scope (by virtue of being an argument).
However, moving/copying it to the outer scope widens the exposure (and lifetime, but not sure to what extent we can actually limit that if introducing the copy-to-clipboard functionality as intended).
For example, consider a scenario where text() is called a second time with invalid input on an existing LD instance:
ld.text('actualsecret');
// at some point later...
ld.text();
This will throw an Error where 'actualsecret' is still in scope. I don't have a PoC or anything but does seem like it could more easily leak to a malicious extension or devtool/debugger integration.
Vs if it's contained in the text function, separate text() invocations are not able to access each others' secrets, and subsequent calls would make new copy instances with isolated scopes wrt secret.
There was a problem hiding this comment.
One way to at least prevent one aspect of scope-creep of secret itself without compromising on the tamper-proofing could be to freeze a property accessor and reassign copy itself instead:
// instead of `let secret`
let _copy = () => Promise.resolve();
async function copy() {
await _copy();
}
// [...]
function text(input) {
_copy = async () = {
// `_copy` can now access `input` from `text` directly
}
}
There was a problem hiding this comment.
I actually just removed c8c9cd7 because:
- it turns out the way i did it dropped a commit coming from main by accident which could have been a terrible mistake
- a younger comment made me realize the implementation isn't right, and that also I'm again not convinced this can be solved without storing the secret in some upper scope
For example, I'm not sure how #50 (comment) demonstrates this otherwise, how scoping a function that has access to the secret instead of the secret itself is far better?
A demonstrating PR here could very much help me understand 🙏
| if (typeof input !== 'string') { | ||
| throw new Error( | ||
| `LavaDomeCore: first argument must be a string, instead got ${stringify(text)}`); | ||
| `LavaDomeCore: first argument must be a string, instead got ${stringify(input)}`); |
There was a problem hiding this comment.
| `LavaDomeCore: first argument must be a string, instead got ${stringify(input)}`); | |
| `LavaDomeCore: first argument must be a string, instead got ${typeof input}`); |
Type should be enough, no need to template secret in error message
| const type = 'text/plain'; | ||
| const blob = new Blob([secret], {type}); | ||
| const data = [new ClipboardItem({[type]: blob})]; | ||
| await write(clipboard, data); |
There was a problem hiding this comment.
Maybe swallow errors on write?
| const type = 'text/plain'; | |
| const blob = new Blob([secret], {type}); | |
| const data = [new ClipboardItem({[type]: blob})]; | |
| await write(clipboard, data); | |
| try { | |
| const type = 'text/plain'; | |
| const blob = new Blob([secret], {type}); | |
| const data = [new ClipboardItem({[type]: blob})]; | |
| // do we also want to return the result of the await here? | |
| await write(clipboard, data); | |
| } finally {} |
There was a problem hiding this comment.
To reduce the likelihood of an error containing a reference to the secret?
There was a problem hiding this comment.
We shouldn't swallow errors that have nothing to do with us, the app should become aware of such errors being thrown. The error will never leak the secret, because if it did, it would have been a major info leak in the design of the native API, which should remain outside of LavaDome's jurisdiction.
boneskull
left a comment
There was a problem hiding this comment.
mostly just questions. I'm not familiar with this (or React)
| } | ||
| } | ||
|
|
||
| export function LavaDome(host, opts) { |
There was a problem hiding this comment.
Is this a constructor? A React component? if the former, why not use class?
There was a problem hiding this comment.
It's the former.
Because there's no way to make methods of a class (truly) private and inaccessible.
There was a problem hiding this comment.
not even with #private? but wait, why do we need to worry about that at all in this use case? I don't see any methods.
There was a problem hiding this comment.
text and the new copy are methods.
They're not assigned to the prototype as methods for the same privacy reason, but they are effectively methods of the instance.
There was a problem hiding this comment.
for the sake of being through, I still don't understand why it needs to be a function and not a class with a constructor impl
There was a problem hiding this comment.
I have to admit I can't think of the reason I used to have when making this decision
boneskull
left a comment
There was a problem hiding this comment.
I'm going to approve this because I don't know any better

close #46 by providing a new LavaDome method
copywhich copies the secret to clipboard without leaking it to any other entity.