|
22 | 22 | } |
23 | 23 |
|
24 | 24 | »*/ |
25 | | -/*DB SCHEMA« |
| 25 | +/*CURRENT DB SCHEMA« |
26 | 26 |
|
27 | 27 | Just like with our local file system, we should have a separate blob storage on the backend. |
28 | 28 |
|
29 | | -The outer "namespaces" (like LOTWFS) are meant to encapsulate the data of the various applications |
| 29 | +The outer "namespaces" (like LOTW_FS) are meant to encapsulate the data of the various (siloed) applications |
30 | 30 | that the backend might possibly be used for. |
31 | 31 |
|
32 | | -root: { |
| 32 | +// Generic read/write rules ($ghid is our numerical github id, and is used as the name of an outer object) |
| 33 | +// ".read": "auth != null", |
| 34 | +// ".write": "auth != null && // Yes we are authorized... |
| 35 | +// auth.provider === 'github' && // by github... |
| 36 | +// auth.token.firebase.identities['github.com'][0] === $ghid && // with the correct id... |
| 37 | +// newData.child('sid').val() == root.child('cur_session_id').val() // identified by the current session |
33 | 38 |
|
34 | | -".read": false, |
35 | | -".write": false, |
36 | | -
|
37 | | -LOTW_FS: { |
| 39 | +MOST RECENT: |
38 | 40 |
|
39 | | - "$ghid": { |
40 | | - session_ids: { // Register a unique session id here upon local initialization |
41 | | - ".validate": "!root.child($ghid).child('session_ids')[newData.val()]" |
42 | | - }, |
43 | | - cur_session_id: { |
44 | | - '.validate": "newData.isString() && newData.val().length >= 4" |
45 | | - }, |
46 | | - next_node_id: { |
47 | | - }, |
48 | | - nodes: { |
49 | | - ".indexOn" = ["parId", "path"], |
50 | | - "$nodeId": { |
51 | | - ".read": "auth != null", |
52 | | - ".write": "auth.ghid = $ghid", |
53 | | - ".validate": "data.exists() || newData.hasChildren(['parId', 'type', 'path'])", |
54 | | - "parId": { // Mutable |
55 | | - ".validate": "newData.isNumber()" |
| 41 | +{ |
| 42 | + "rules": { |
| 43 | + ".read": false, |
| 44 | + ".write": false, |
| 45 | + "LOTW_FS": { |
| 46 | + "$ghid": { |
| 47 | + "session_ids": { |
| 48 | + "$sid":{ |
| 49 | + ".read": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid", |
| 50 | + ".write": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid", |
| 51 | + ".validate": "newData.isBoolean() && newData.val() === true && !root.child('LOTW_FS').child($ghid).child('session_ids').child($sid).exists()" |
| 52 | + } |
56 | 53 | }, |
57 | | - "path": { // Mutable: parId/name |
58 | | - ".validate": "newData.isString() && newData.val().length < $PATH_MAX" |
| 54 | + "cur_session_id": { |
| 55 | + ".read": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid", |
| 56 | + ".write": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid && newData.child('sid').val() === root.child('cur_session_id').val()", |
| 57 | + ".validate": "newData.isString() && newData.val().length == 4" |
59 | 58 | }, |
60 | | - "type": { |
61 | | - ".validate": "!data.exists() && newData.isString() && newData.val().length < $TYPE_MAX" |
| 59 | + "next_node_id": { |
| 60 | + ".read": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid", |
| 61 | + ".write": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid && newData.child('sid').val() === root.child('cur_session_id').val()", |
| 62 | + ".validate": true |
62 | 63 | }, |
63 | | - "blobId": { |
64 | | - ".validate": "!data.exists() && newData.isString() && newData.val().length < $ID_MAX" |
65 | | - } |
66 | | - "$other": { |
67 | | - ".validate": false |
68 | | - } |
69 | | - } |
70 | | - }, |
71 | | - blobs: { |
72 | | - "$blobId": { |
73 | | - "meta": { // Example |
74 | | - "field1": { |
75 | | - ".validate": "newData.isString() && newData.val().length < $FIELD1_MAX" |
76 | | - }, |
77 | | - "field2": { |
78 | | - ".validate": "newData.isNumber()" |
79 | | - }, |
80 | | - "field3": { |
81 | | - ".validate": "newData.isBoolean()" |
82 | | - }, |
83 | | - ".other": { |
84 | | - ".validate": false |
| 64 | + "nodes": { |
| 65 | + ".indexOn": ["parId", "path"], |
| 66 | + "$nodeId": { |
| 67 | + ".read": "auth != null && auth.provider === 'github'", |
| 68 | + ".write": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid && newData.child('sid').val() === root.child('cur_session_id').val()", |
| 69 | + ".validate": "data.exists() || newData.hasChildren(['parId', 'type', 'path'])", |
| 70 | + "parId": { |
| 71 | + ".validate": "newData.isNumber()" |
| 72 | + }, |
| 73 | + "path": { |
| 74 | + ".validate": "newData.isString() && newData.val().length < 100" |
| 75 | + }, |
| 76 | + "type": { |
| 77 | + ".validate": "!data.exists() && newData.isString() && newData.val().length < 5" |
| 78 | + }, |
| 79 | + "blobId": { |
| 80 | + ".validate": "!data.exists() && newData.isNumber()" |
| 81 | + }, |
| 82 | + "$other": { |
| 83 | + ".validate": false |
| 84 | + } |
85 | 85 | } |
86 | 86 | }, |
87 | | - "contents": { |
88 | | - ".validate": "newData.isString() && newData.val().length < $CONTENTS_MAX" |
89 | | - }, |
90 | | - "$other": { |
91 | | - ".validate": false |
| 87 | + "blobs": { |
| 88 | + "$blobId": { |
| 89 | + ".read": "auth != null && auth.provider === 'github'", |
| 90 | + ".write": "auth != null && auth.provider === 'github' && auth.token.firebase.identities['github.com'][0] === $ghid && newData.child('sid').val() === root.child('cur_session_id').val()", |
| 91 | + "meta": { |
| 92 | + ".validate": true |
| 93 | + }, |
| 94 | + "contents": { |
| 95 | + ".validate": "newData.isString() && newData.val().length < 100000" |
| 96 | + }, |
| 97 | + "$other": { |
| 98 | + ".validate": false |
| 99 | + } |
| 100 | + } |
92 | 101 | } |
93 | 102 | } |
94 | 103 | } |
95 | 104 | } |
96 | | -}, |
| 105 | +} |
97 | 106 |
|
98 | | -OTHER_NS: { |
| 107 | +Also: Let's await on update. |
| 108 | +»*/ |
99 | 109 |
|
100 | | -} |
| 110 | +/*10/11/25: The urgency is arising. First, we'll delete everything from the firebase datastore,« |
| 111 | +and replace the security rules, whole cloth, with our new ones (the DB SCHEMA). Then we'll put |
| 112 | +this file in another location, and start it over again. We are going to need to clean up the |
| 113 | +logic that we've recently added to sys/fs.js. The plan is to do a 1:1 mapping of the |
| 114 | +(indexedDB) database logic used in sys/fs.js. |
101 | 115 |
|
| 116 | +Way more than that stupid crap (below) about hardware APIs there is a need of a central location for, |
| 117 | +and common interface into all of the various ways of interacting, computationally-speaking, |
| 118 | +with the wider world. |
102 | 119 |
|
103 | | -} |
| 120 | +»*/ |
| 121 | +/*10/9/25: The fundamental idea I am having is to do only what is necessary to support an« |
| 122 | +"ecosystem" that is centered around web-client-centric scripting languages. |
104 | 123 |
|
105 | | -Also: Let's await on update. |
| 124 | +One of the more telling outcomes will/should be the increasing usage of (web-based) hardware |
| 125 | +APIs, as opposed to DOM APIs. |
106 | 126 | »*/ |
| 127 | +/*10/7/25: Overall workflow« |
| 128 | +
|
| 129 | +1. Load the net.fs library |
| 130 | +2. Get the current user object |
| 131 | + - If not found, the user can only proceed by logging in |
| 132 | +3. Once logged in, check that a remote user directory has been set up. |
| 133 | + - If none exists, the user must create one. |
| 134 | +4. Check for the session id ($sid) in local storage. |
| 135 | + - If not found, call create_session_id() until an unused one is found, and set it in local storage. |
| 136 | +5. Call set_session_id() with the value of $sid. |
| 137 | +6. Perform remote fs operations. |
| 138 | + - If these fail with permission denied (on one's own directory), this most likely means that |
| 139 | + another session has called set_session_id. Report this (likely) error condition, and inform |
| 140 | + the user that they must manually reset the session id to continue. |
107 | 141 |
|
| 142 | +»*/ |
108 | 143 | /*10/6/25: Persistent session ids, create_new_file() example« |
109 | 144 |
|
110 | 145 | Let's do persistent 24 bit session ids (4 chars, ~16M possible). This is instead of |
@@ -1885,6 +1920,87 @@ export {coms, onkill}; |
1885 | 1920 | cwarn("Firebase config"); |
1886 | 1921 | log(firebaseConfig); |
1887 | 1922 |
|
| 1923 | + |
| 1924 | + |
| 1925 | + |
| 1926 | + |
| 1927 | +/*« |
| 1928 | +
|
| 1929 | +PAST: |
| 1930 | +
|
| 1931 | +root: { |
| 1932 | +
|
| 1933 | +".read": false, |
| 1934 | +".write": false, |
| 1935 | +
|
| 1936 | +LOTW_FS: { |
| 1937 | +
|
| 1938 | + "$ghid": { |
| 1939 | + session_ids: { // Register a unique session id here upon local initialization, stored locally |
| 1940 | + ".validate": "!root.child($ghid).child('session_ids')[newData.val()]" |
| 1941 | + }, |
| 1942 | + cur_session_id: { |
| 1943 | + '.validate": "newData.isString() && newData.val().length == 4" |
| 1944 | + }, |
| 1945 | + next_node_id: { |
| 1946 | + }, |
| 1947 | + nodes: { |
| 1948 | + ".indexOn" = ["parId", "path"], |
| 1949 | + "$nodeId": { |
| 1950 | + ".read": "auth != null", |
| 1951 | + ".write": "auth.ghid = $ghid", |
| 1952 | + ".validate": "data.exists() || newData.hasChildren(['parId', 'type', 'path'])", |
| 1953 | + "parId": { // Mutable |
| 1954 | + ".validate": "newData.isNumber()" |
| 1955 | + }, |
| 1956 | + "path": { // Mutable: parId/name |
| 1957 | + ".validate": "newData.isString() && newData.val().length < $PATH_MAX" |
| 1958 | + }, |
| 1959 | + "type": { |
| 1960 | + ".validate": "!data.exists() && newData.isString() && newData.val().length < $TYPE_MAX" |
| 1961 | + }, |
| 1962 | + "blobId": { |
| 1963 | + ".validate": "!data.exists() && newData.isString() && newData.val().length < $ID_MAX" |
| 1964 | + } |
| 1965 | + "$other": { |
| 1966 | + ".validate": false |
| 1967 | + } |
| 1968 | + } |
| 1969 | + }, |
| 1970 | + blobs: { |
| 1971 | + "$blobId": { |
| 1972 | + "meta": { // Example |
| 1973 | + "field1": { |
| 1974 | + ".validate": "newData.isString() && newData.val().length < $FIELD1_MAX" |
| 1975 | + }, |
| 1976 | + "field2": { |
| 1977 | + ".validate": "newData.isNumber()" |
| 1978 | + }, |
| 1979 | + "field3": { |
| 1980 | + ".validate": "newData.isBoolean()" |
| 1981 | + }, |
| 1982 | + ".other": { |
| 1983 | + ".validate": false |
| 1984 | + } |
| 1985 | + }, |
| 1986 | + "contents": { |
| 1987 | + ".validate": "newData.isString() && newData.val().length < $CONTENTS_MAX" |
| 1988 | + }, |
| 1989 | + "$other": { |
| 1990 | + ".validate": false |
| 1991 | + } |
| 1992 | + } |
| 1993 | + } |
| 1994 | + } |
| 1995 | +}, |
| 1996 | +
|
| 1997 | +OTHER_NS: { |
| 1998 | +
|
| 1999 | +} |
| 2000 | +
|
| 2001 | +} |
| 2002 | +
|
| 2003 | +»*/ |
1888 | 2004 | /*« |
1889 | 2005 | goog_but.onclick=async()=>{//« |
1890 | 2006 | is_active = true; |
@@ -1929,3 +2045,4 @@ const firebaseConfig = { |
1929 | 2045 | appId: "1:668423415088:web:979b40c704cab2322ed4f5" |
1930 | 2046 | }; |
1931 | 2047 | »*/ |
| 2048 | + |
0 commit comments