Share a secret across ES6 specific modules, so that other modules cannot access the secret?

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Share a secret across ES6 specific modules, so that other modules cannot access the secret?

/#!/JoePea
Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

Jordan Harband
Nope. This is exactly why it seems that "protected" couldn't have any way to work that has "hard" enforcement.

The only true privacy in JS is via closure (including WeakMaps), or via the upcoming "private fields" proposal, assuming it stays as "hard private". Anything shared is publicly accessible.

I'd be very interested to hear any idea that would allow modules A and B to privately share something, without module C being able to; the only thing I could think of would be some sort of private export that explicitly included a list of module specifiers that were allowed to import it - which would still not be secure whenever loader hooks exist.

On Sun, Apr 23, 2017 at 1:42 PM, /#!/JoePea <[hidden email]> wrote:
Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

Bradley Meck
To an extent, yes. You can use hoisting of function declarations and circular dependencies to create a "gateway". During circular dependencies, you have a time where function declarations are available but evaluation has not occured. During that time you can setup your private state. Then, immediately on evaluation, remove your gateway.

```
// file: ./secrets

// import all friendly modules (note: all dependencies of these modules could access GATEWAY)
import './a'
GATEWAY = void 0;


// storage for shared secrets
let SECRET;
// gateway
function GATEWAY() {
  if (!SECRET) SECRET = {};
  return SECRET;
}
export {GATEWAY};
```

```
// file: ./a
import {GATEWAY} from './secrets';
if (typeof GATEWAY !== 'function') {
  throw Error('import secrets *first*.');
}
const SECRET = GATEWAY();
```

With Realms (https://github.com/tc39/proposal-realms) you may be able to use the completion value of Module Evaluation to also achieve a way to share private state in a more sane way. VM implementations allow this in some ways as well : https://github.com/v8/v8/blob/a71c338d9e24e55b47125108a0fce754076751d0/include/v8.h#L1109

On Sun, Apr 23, 2017 at 6:02 PM, Jordan Harband <[hidden email]> wrote:
Nope. This is exactly why it seems that "protected" couldn't have any way to work that has "hard" enforcement.

The only true privacy in JS is via closure (including WeakMaps), or via the upcoming "private fields" proposal, assuming it stays as "hard private". Anything shared is publicly accessible.

I'd be very interested to hear any idea that would allow modules A and B to privately share something, without module C being able to; the only thing I could think of would be some sort of private export that explicitly included a list of module specifiers that were allowed to import it - which would still not be secure whenever loader hooks exist.

On Sun, Apr 23, 2017 at 1:42 PM, /#!/JoePea <[hidden email]> wrote:
Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

Allen Wirfs-Brock

On Apr 24, 2017, at 12:34 PM, Bradley Meck <[hidden email]> wrote:

To an extent, yes. You can use hoisting of function declarations and circular dependencies to create a "gateway". During circular dependencies, you have a time where function declarations are available but evaluation has not occured. During that time you can setup your private state. Then, immediately on evaluation, remove your gateway.

```
// file: ./secrets

// import all friendly modules (note: all dependencies of these modules could access GATEWAY)
import './a'
GATEWAY = void 0;


// storage for shared secrets
let SECRET;

Really clever! 

Doesn’t this need to be a `var` declaration.  Otherwise, the initial test of SECRET will be in its TDZ the first time GATEWAY is called.


// gateway
function GATEWAY() {
  if (!SECRET) SECRET = {};
  return SECRET;
}
export {GATEWAY};
```

```
// file: ./a
import {GATEWAY} from './secrets';
if (typeof GATEWAY !== 'function') {
  throw Error('import secrets *first*.');
}
const SECRET = GATEWAY();
```

With Realms (https://github.com/tc39/proposal-realms) you may be able to use the completion value of Module Evaluation to also achieve a way to share private state in a more sane way. VM implementations allow this in some ways as well : https://github.com/v8/v8/blob/a71c338d9e24e55b47125108a0fce754076751d0/include/v8.h#L1109



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

Bradley Meck
Ah yes, my bad. `var`!

On Mon, Apr 24, 2017 at 3:43 PM, Allen Wirfs-Brock <[hidden email]> wrote:

On Apr 24, 2017, at 12:34 PM, Bradley Meck <[hidden email]> wrote:

To an extent, yes. You can use hoisting of function declarations and circular dependencies to create a "gateway". During circular dependencies, you have a time where function declarations are available but evaluation has not occured. During that time you can setup your private state. Then, immediately on evaluation, remove your gateway.

```
// file: ./secrets

// import all friendly modules (note: all dependencies of these modules could access GATEWAY)
import './a'
GATEWAY = void 0;


// storage for shared secrets
let SECRET;

Really clever! 

Doesn’t this need to be a `var` declaration.  Otherwise, the initial test of SECRET will be in its TDZ the first time GATEWAY is called.


// gateway
function GATEWAY() {
  if (!SECRET) SECRET = {};
  return SECRET;
}
export {GATEWAY};
```

```
// file: ./a
import {GATEWAY} from './secrets';
if (typeof GATEWAY !== 'function') {
  throw Error('import secrets *first*.');
}
const SECRET = GATEWAY();
```

With Realms (https://github.com/tc39/proposal-realms) you may be able to use the completion value of Module Evaluation to also achieve a way to share private state in a more sane way. VM implementations allow this in some ways as well : https://github.com/v8/v8/blob/a71c338d9e24e55b47125108a0fce754076751d0/include/v8.h#L1109




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

doodad-js Admin
In reply to this post by Jordan Harband

If you are interested to look at it, I’ve implemented a module loader with a secret shared across the Doodad framework (1)(2) and not available outside that framework. A Doodad module consists of only one export (an “add” function) that injects the module payload into an object. That payload has some metadata and a “create” function that receives the root namespace (public) and shared stuff (protected, like the secret).

  1. https://www.npmjs.com/package/doodad-js
  2. https://github.com/doodadjs/doodad-js

 

(I’m French, so please excuse me if I don’t elaborate more and/or if my English is not accurate)

 

From: Jordan Harband [mailto:[hidden email]]
Sent: Sunday, April 23, 2017 7:03 PM
To: /#!/JoePea <[hidden email]>
Cc: es-discuss <[hidden email]>
Subject: Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

 

Nope. This is exactly why it seems that "protected" couldn't have any way to work that has "hard" enforcement.

 

The only true privacy in JS is via closure (including WeakMaps), or via the upcoming "private fields" proposal, assuming it stays as "hard private". Anything shared is publicly accessible.

 

I'd be very interested to hear any idea that would allow modules A and B to privately share something, without module C being able to; the only thing I could think of would be some sort of private export that explicitly included a list of module specifiers that were allowed to import it - which would still not be secure whenever loader hooks exist.

 

On Sun, Apr 23, 2017 at 1:42 PM, /#!/JoePea <[hidden email]> wrote:

Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

 

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?


/#!/JoePea


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

 


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

/#!/JoePea
In reply to this post by Bradley Meck
> GATEWAY

That's an interesting idea, Bradley, thanks! I originally wanted this for implementing "protected" class members (i.e. sharing a WeakMap across subclasses in different files), but I've since done this another way that is even better: https://github.com/trusktr/lowclass.

With lowclass we can also make what I'm calling "module protected" access (similar to "friends" in C or "package protected" in Java) by simply leaking access helpers to outside scope inside a module. Here's the example in the README.

But now that I've revisited this thread, I realize that with a GATEWAY it is possible to share a "leaked" access helper across files too, thus making something that is more like Java's "package protected"! Cool!

> note: all dependencies of these modules could access GATEWAY

This can be prevented by having the `GATEWAY` function count how many times it is called. If we hard code the number of modules that will call GATEWAY in a project, we can throw an error if the number of accesses is higher than expected and blatantly breaking an app to force people not to do it. Automated tests can ensure that the number is hard coded properly. It could also be possible to add a build step to automatically detect and add the hard-coded number.

> With Realms

That's also interesting, but I think it would be too heavy-weight to create new JS contexts just for sharing some private references. The GATEWAY idea I think is much slimmer. Plus sharing across Realms can introduce all sorts of other problems like `instanceof` checks failing due to one global not being the same reference to the equivalent global in the other realm (`console.assert(window.Object !== realm.Object)`). Here's is the same problem with Jest (with Node's `vm` rather than Realms, but essentially its the same issue).

It'd be better if there were some sort of spec added to Modules that allowed some set of modules to import private exports from each other with simple syntax, or similar. Maybe it would be based on folder structure, or maybe module identifiers referenced in each other so that there's no physical circular dependency, only harmless circular mentioning of each other at worst, so that runtime circular dependency issues don't become a problem.

> If you are interested to look at it, I’ve implemented a module loader with a secret shared across the Doodad framework

Thanks for sharing that Claude. It's interesting to see how others are implementing public/protected/private for their classes. :)

- Joe

/#!/JoePea

On Mon, Apr 24, 2017 at 12:34 PM, Bradley Meck <[hidden email]> wrote:
To an extent, yes. You can use hoisting of function declarations and circular dependencies to create a "gateway". During circular dependencies, you have a time where function declarations are available but evaluation has not occured. During that time you can setup your private state. Then, immediately on evaluation, remove your gateway.

```
// file: ./secrets

// import all friendly modules (note: all dependencies of these modules could access GATEWAY)
import './a'
GATEWAY = void 0;


// storage for shared secrets
let SECRET;
// gateway
function GATEWAY() {
  if (!SECRET) SECRET = {};
  return SECRET;
}
export {GATEWAY};
```

```
// file: ./a
import {GATEWAY} from './secrets';
if (typeof GATEWAY !== 'function') {
  throw Error('import secrets *first*.');
}
const SECRET = GATEWAY();
```

With Realms (https://github.com/tc39/proposal-realms) you may be able to use the completion value of Module Evaluation to also achieve a way to share private state in a more sane way. VM implementations allow this in some ways as well : https://github.com/v8/v8/blob/a71c338d9e24e55b47125108a0fce754076751d0/include/v8.h#L1109

On Sun, Apr 23, 2017 at 6:02 PM, Jordan Harband <[hidden email]> wrote:
Nope. This is exactly why it seems that "protected" couldn't have any way to work that has "hard" enforcement.

The only true privacy in JS is via closure (including WeakMaps), or via the upcoming "private fields" proposal, assuming it stays as "hard private". Anything shared is publicly accessible.

I'd be very interested to hear any idea that would allow modules A and B to privately share something, without module C being able to; the only thing I could think of would be some sort of private export that explicitly included a list of module specifiers that were allowed to import it - which would still not be secure whenever loader hooks exist.

On Sun, Apr 23, 2017 at 1:42 PM, /#!/JoePea <[hidden email]> wrote:
Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

Mike Samuel
In reply to this post by /#!/JoePea
The box function defined in github.com/mikesamuel/tc39-module-keys enables things like this.


On Sun, Apr 23, 2017 at 4:42 PM, /#!/JoePea <[hidden email]> wrote:
Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

/#!/JoePea
Ah, interesting! That would be useful!

/#!/JoePea

On Sun, Apr 15, 2018 at 11:58 AM, Mike Samuel <[hidden email]> wrote:
The box function defined in github.com/mikesamuel/tc39-module-keys enables things like this.


On Sun, Apr 23, 2017 at 4:42 PM, /#!/JoePea <[hidden email]> wrote:
Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

/#!/JoePea
In reply to this post by Mike Samuel
I think it'd be nice if there was something also easier, based only on file names or directory structure.

```js
// log-foo.js
import Foo from './Foo'
console.log(Foo)
```

```js
// Foo.js
class Foo {}
export Foo for './log-foo'

// or with expressions, all files in this folder
export Foo for './*'
```

I know, someone can stick a file in there then, but at least it gives a "don't mess with this unless you know what you're doing" message like many other things in JavaScript (f.e. redefining a configurable property even if writable is false).

We'll, I suppose even with public keys, a use can just replace your module in the file system with their own, so the same "be careful" principal still applies there.

Of course, network-modules won't have the filesystem-module problem, so probably both filename approach and box approach would be secure with network modules (just needs infrastructure for passing that info around).

On Sun, Apr 15, 2018, 11:58 AM Mike Samuel <[hidden email]> wrote:
The box function defined in github.com/mikesamuel/tc39-module-keys enables things like this.


On Sun, Apr 23, 2017 at 4:42 PM, /#!/JoePea <[hidden email]> wrote:
Is there a way to share some secret value across a few modules, and prevent other modules? f.e. prevent modules of an app dev who is importing modules of a library where the library wants to share private stuff across its modules. Is this possible to implement somehow?

WeakMaps can be encapsulated inside a module to implement "private" properties for a class defined inside that module and then exported. But "protected" can't be implemented with a WeakMap shared with modules because then end-user app code can import the WeakMap and read all the stuff. Is there some way to share a WeakMap private with classes defined across modules?

/#!/JoePea

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Share a secret across ES6 specific modules, so that other modules cannot access the secret?

Isiah Meadows-2
Related relevant proposal/strawman/whatever:

- https://github.com/isiahmeadows/private-data-proposal
- https://github.com/tc39/proposal-class-fields/issues/94
- https://github.com/zenparsing/js-classes-1.1/issues/44

And in particular in the first linked issue, I did propose an `export
{ ... } to "./foo.js"` here:

https://github.com/tc39/proposal-class-fields/issues/94#issuecomment-381626341

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Mon, Apr 16, 2018 at 12:24 PM, /#!/JoePea <[hidden email]> wrote:

> I think it'd be nice if there was something also easier, based only on file
> names or directory structure.
>
> ```js
> // log-foo.js
> import Foo from './Foo'
> console.log(Foo)
> ```
>
> ```js
> // Foo.js
> class Foo {}
> export Foo for './log-foo'
>
> // or with expressions, all files in this folder
> export Foo for './*'
> ```
>
> I know, someone can stick a file in there then, but at least it gives a
> "don't mess with this unless you know what you're doing" message like many
> other things in JavaScript (f.e. redefining a configurable property even if
> writable is false).
>
> We'll, I suppose even with public keys, a use can just replace your module
> in the file system with their own, so the same "be careful" principal still
> applies there.
>
> Of course, network-modules won't have the filesystem-module problem, so
> probably both filename approach and box approach would be secure with
> network modules (just needs infrastructure for passing that info around).
>
> On Sun, Apr 15, 2018, 11:58 AM Mike Samuel <[hidden email]> wrote:
>>
>> The box function defined in github.com/mikesamuel/tc39-module-keys enables
>> things like this.
>>
>>
>> On Sun, Apr 23, 2017 at 4:42 PM, /#!/JoePea <[hidden email]> wrote:
>>>
>>> Is there a way to share some secret value across a few modules, and
>>> prevent other modules? f.e. prevent modules of an app dev who is importing
>>> modules of a library where the library wants to share private stuff across
>>> its modules. Is this possible to implement somehow?
>>>
>>> WeakMaps can be encapsulated inside a module to implement "private"
>>> properties for a class defined inside that module and then exported. But
>>> "protected" can't be implemented with a WeakMap shared with modules because
>>> then end-user app code can import the WeakMap and read all the stuff. Is
>>> there some way to share a WeakMap private with classes defined across
>>> modules?
>>>
>>> /#!/JoePea
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> [hidden email]
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss