{"action":"created","issue":{"url":"https://api.github.com/repos/Jasonette/documentation/issues/56","repository_url":"https://api.github.com/repos/Jasonette/documentation","labels_url":"https://api.github.com/repos/Jasonette/documentation/issues/56/labels{/name}","comments_url":"https://api.github.com/repos/Jasonette/documentation/issues/56/comments","events_url":"https://api.github.com/repos/Jasonette/documentation/issues/56/events","html_url":"https://github.com/Jasonette/documentation/issues/56","id":227847581,"number":56,"title":"Spec for the NEW sandboxed Local Storage - Feedback appreciated","user":{"login":"gliechtenstein","id":16613330,"avatar_url":"https://avatars3.githubusercontent.com/u/16613330?v=3","gravatar_id":"","url":"https://api.github.com/users/gliechtenstein","html_url":"https://github.com/gliechtenstein","followers_url":"https://api.github.com/users/gliechtenstein/followers","following_url":"https://api.github.com/users/gliechtenstein/following{/other_user}","gists_url":"https://api.github.com/users/gliechtenstein/gists{/gist_id}","starred_url":"https://api.github.com/users/gliechtenstein/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gliechtenstein/subscriptions","organizations_url":"https://api.github.com/users/gliechtenstein/orgs","repos_url":"https://api.github.com/users/gliechtenstein/repos","events_url":"https://api.github.com/users/gliechtenstein/events{/privacy}","received_events_url":"https://api.github.com/users/gliechtenstein/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":7,"created_at":"2017-05-11T00:36:06Z","updated_at":"2017-05-19T01:43:21Z","closed_at":null,"body":"One of the most frequently requested features is local key/value storage. This is a sensitive problem since it's directly related to security. Browsers have sandboxing for many good reasons. This is why I've been delaying making a decision on this until I've come up with a couple of ideas. \r\n\r\nNow I have, and wanted to share. Note that none of the ideas involve having a single global storage, but involves having a local storage sandbox per each URL and accessing them from one view to another.\r\n\r\nHere are the two:\r\n\r\n# 1. Readonly exports\r\nIf you are aware of javascript module system you can think of this as a similar method. We would introduce two new actions `$state.export` and `$state.import`. Users would need to first visit a URL to \"export\" all the values it wants to export, and then once that's done, other views can reference the value using `$state.import`. If you try to `$state.import` before it's been exported, it will not return the value;\r\n\r\nI actually took a shot at a quick prototype over at [$state branch](https://github.com/Jasonette/JASONETTE-iOS/blob/%24state/app/Jasonette/JasonStateAction.m) The code is commented so it should be self-explanatory how it should work. \r\n\r\n- Pros: it's pretty simple (conceptually as well as implementation-wise) and intuitive. Easy to implement.\r\n- Cons: the states are \"readonly\" from other views. You can write to the state of any URL ONLY from itself.\r\n\r\nAn example code:\r\n\r\nExporting:\r\n\r\n```json\r\n    {\r\n        \"type\": \"$state.export\",\r\n        \"options\": {\r\n            \"username\": \"Ethan\",\r\n            \"email\": \"ethan.gliechtenstein@gmail.com\"\r\n        },\r\n        \"success\": {\r\n            \"type\": \"$close\"\r\n        }\r\n    }\r\n```\r\n\r\nImporting\r\n\r\n```json\r\n     {\r\n        \"type\": \"$state.import\",\r\n        \"options\": {\r\n            \"db\": \"https://www.jasonbase.com/things/3nf.json\"\r\n        },\r\n        \"success\": {\r\n            \"type\": \"$set\",\r\n            \"options\": {\r\n                \"db\": \"{{$jason.db}}\"\r\n            }\r\n        }\r\n     }\r\n```\r\n\r\nIt works pretty similarly to how Javascript module system works. you can export and other modules can import to use them, but they are readonly (the similarity to Javascript module system is another reason why this feels simpler)\r\n\r\nBut like I said, not being able to write has some drawbacks, which is why I have another idea:\r\n\r\n# 2. Read/Write state variables\r\n\r\nHere, you not only can read from another URL's state, but also can write to it. Here the API would consist of: `$state.set` and `$state.get`. \r\n\r\nSince being able to write to another view's sandbox is a big deal in terms of security, we also need another security measure. In this case we will also need to explicitly state the public state variables so that only those state variables can be set from outside of the view. This may look something like this:\r\n\r\n```json\r\n{\r\n  \"$jason\": {\r\n    \"head\": {\r\n      \"state\": [\"username\", \"email\"],\r\n      ...\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nBasically we are stating that anyone can set the state variable for this URL but ONLY the \"username\" and \"email\" variables.\r\n\r\nI've attached below a full example of what it would look like. But before we go on, just a quick explanation on how this works:\r\n\r\n1. abc.json is the master view which transitions to 123.json\r\n2. User can select an option from 123.json\r\n3. When the user selects an item, it sets the `abc.json`'s `selected` state variable via `$state.set`, and returns via `$back` action.\r\n4. When we return to `abc.json`, the `$show` event triggers `$state.get` and renders the view based on the state we've just set.\r\n\r\nabc.json\r\n\r\n```json\r\n{\r\n  \"$jason\": {\r\n    \"head\": {\r\n      \"state\": [\"selected\"],\r\n      \"actions\": {\r\n        \"$show\": {\r\n          \"type\": \"$state.get\",\r\n          \"options\": {\r\n            \"db\": \"https://www.jasonbase.com/things/abc.json\"\r\n          },\r\n          \"success\": [{\r\n            \"{{#if ('db' in $jason) && ('selected' in $jason.db)}}\": {\r\n              \"type\": \"$set\",\r\n              \"options\": {\r\n                \"selected\": \"{{$jason.db.selected}}\"\r\n              },\r\n              \"success\": {\r\n                \"type\": \"$render\"\r\n              }\r\n            }\r\n          }, {\r\n            \"{{#else}}\": {\r\n              \"type\": \"$set\",\r\n              \"options\": {\r\n                \"selected\": \"Nothing selected\"\r\n              },\r\n              \"success\": {\r\n                \"type\": \"$render\"\r\n              }\r\n            }\r\n          }]\r\n        }\r\n      },\r\n      \"templates\": {\r\n        \"body\": {\r\n          \"sections\": [{\r\n            \"header\": {\r\n              \"type\": \"label\",\r\n              \"text\": \"{{$get.selected}}\"\r\n            },\r\n            \"items\": [{\r\n              \"type\": \"label\",\r\n              \"text\": \"Select Items\",\r\n              \"href\": {\r\n                \"url\": \"https://www.jasonbase.com/things/123.json\"\r\n              }\r\n            }]\r\n          }]\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n\r\n123.json\r\n```json\r\n{\r\n  \"$jason\": {\r\n    \"head\": {\r\n      \"data\": {\r\n        \"items\": [{\r\n          \"text\": \"Item 1\"\r\n        }, {\r\n          \"text\": \"Item 2\"\r\n        }, {\r\n          \"text\": \"Item 3\"\r\n        }]\r\n      },\r\n      \"templates\": {\r\n        \"body\": {\r\n          \"sections\": [{\r\n            \"items\": {\r\n              \"{{#each items}}\": {\r\n                \"type\": \"label\",\r\n                \"text\": \"{{text}}\",\r\n                \"action\": {\r\n                  \"type\": \"$state.set\",\r\n                  \"options\": {\r\n                    \"selected@https://www.jasonbase.com/things/abc.json\": \"{{text}}\"\r\n                  },\r\n                  \"success\": {\r\n                    \"type\": \"$back\"\r\n                  }\r\n                }\r\n              }\r\n            }\r\n          }]\r\n        }\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n- pros: more flexible\r\n- cons: \r\n  1. more complex, which means there can be some unforeseen edge cases.\r\n  2. This one's more important: Because we rely on the \"state\" declaration on the view in order to determine what state variable is read/writeable, every time we access `$state.get`, we need to query the the state's owner URL (one network/file request) to check its `$jason.head.state` attribute to make sure the attribute has been declared accessible. (The first solution I suggested above doesn't have this problem since the variable will simply be empty if it hasn't been already exported)\r\n\r\n---\r\n\r\n# Feedback appreciated\r\n\r\nI wanted to share here because I'm still trying to decide on this since people have been requesting this either directly or indirectly (a lot of the problems people talk about on the forum can be made easier by supporting this, for example almost all bugs/issues related to tab bar or $params will become irrelevant when we support this since we can deprecate $params and just use the `$state` instead, which is much more robust and flexible).\r\n\r\n**I would appreciate any kind of feedback on either of the two.** Especially if you have a better idea or improvement, or any security holes I missed, please feel free to share.\r\n\r\nThanks!"},"comment":{"url":"https://api.github.com/repos/Jasonette/documentation/issues/comments/302586392","html_url":"https://github.com/Jasonette/documentation/issues/56#issuecomment-302586392","issue_url":"https://api.github.com/repos/Jasonette/documentation/issues/56","id":302586392,"user":{"login":"gliechtenstein","id":16613330,"avatar_url":"https://avatars3.githubusercontent.com/u/16613330?v=3","gravatar_id":"","url":"https://api.github.com/users/gliechtenstein","html_url":"https://github.com/gliechtenstein","followers_url":"https://api.github.com/users/gliechtenstein/followers","following_url":"https://api.github.com/users/gliechtenstein/following{/other_user}","gists_url":"https://api.github.com/users/gliechtenstein/gists{/gist_id}","starred_url":"https://api.github.com/users/gliechtenstein/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gliechtenstein/subscriptions","organizations_url":"https://api.github.com/users/gliechtenstein/orgs","repos_url":"https://api.github.com/users/gliechtenstein/repos","events_url":"https://api.github.com/users/gliechtenstein/events{/privacy}","received_events_url":"https://api.github.com/users/gliechtenstein/received_events","type":"User","site_admin":false},"created_at":"2017-05-19T01:43:21Z","updated_at":"2017-05-19T01:43:21Z","body":"> In the data-per-url scheme, would it be beneficial to think of only allowing certain other urls/views to access protected keys?\r\n\r\n@Joshfindit Yes that was the idea. In case of the second spec (which I am leaning towards), there's an attribute called `state`, which will just be an array of accessible attributes for the initial release, but eventually it will contain something like a key value pair of security info such as:\r\n\r\n```\r\nstate: [{\r\n  \"username\": {\r\n    \"read\": \"*\",\r\n    \"write\": \"https://jasonbase.com/things/3nf.json\"\r\n  }\r\n}]\r\n```\r\n\r\nIn this case the `username` attribute is readable from all urls but only writable by the specified URL, or something like that. But I don't want to think too deep into this yet since the first version isn't even out yet. Probably will go with the \"allow all\" approach as the first version"}}
{"actor":{"display_login":"gliechtenstein"}}