Răsfoiți Sursa

dev: add user-app to permission scanning

KernelDeimos 10 luni în urmă
părinte
comite
4a6055d239

+ 68 - 0
src/backend/src/data/hardcoded-permissions.js

@@ -0,0 +1,68 @@
+const default_implicit_user_app_permissions = {
+    'driver:helloworld:greet': {},
+    'driver:puter-kvstore': {},
+    'driver:puter-ocr:recognize': {},
+    'driver:puter-chat-completion': {},
+    'driver:puter-image-generation': {},
+    'driver:puter-tts': {},
+    'driver:puter-apps': {},
+    'driver:puter-subdomains': {},
+    'driver:temp-email': {},
+};
+
+const implicit_user_app_permissions = [
+    {
+        id: 'builtin-apps',
+        apps: [
+            'app-0bef044f-918f-4cbf-a0c0-b4a17ee81085', // about
+            'app-838dfbc4-bf8b-48c2-b47b-c4adc77fab58', // editor
+            'app-58282b08-990a-4906-95f7-fa37ff92452b', // draw
+            'app-0087b701-da09-4f49-a37d-2d6bcabc81ee', // minipaint
+            'app-3fea7529-266e-47d9-8776-31649cd06557', // terminal
+            'app-5584fbf7-ed69-41fc-99cd-85da21b1ef51', // camera
+            'app-7bdca1a4-6373-4c98-ad97-03ff2d608ca1', // recorder
+            'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77', // dev-center
+            'app-a2ae72a4-1ba3-4a29-b5c0-6de1be5cf178', // app-center
+            'app-74378e84-b9cd-5910-bcb1-3c50fa96d6e7', // https://nj.puter.site
+            'app-13a38aeb-f9f6-54f0-9bd3-9d4dd655ccfe', // https://cdpn.io
+            'app-dce8f797-82b0-5d95-a2f8-ebe4d71b9c54', // https://null.jsbin.com
+            'app-93005ce0-80d1-50d9-9b1e-9c453c375d56', // https://markus.puter.com
+        ],
+        permissions: {
+            'driver:helloworld:greet': {},
+            'driver:puter-ocr:recognize': {},
+            'driver:puter-kvstore:get': {},
+            'driver:puter-kvstore:set': {},
+            'driver:puter-kvstore:del': {},
+            'driver:puter-kvstore:list': {},
+            'driver:puter-kvstore:flush': {},
+            'driver:puter-chat-completion:complete': {},
+            'driver:puter-image-generation:generate': {},
+            'driver:puter-analytics:create_trace': {},
+            'driver:puter-analytics:record': {},
+        },
+    },
+    {
+        id: 'local-testing',
+        apps: [
+            'app-a392f3e5-35ca-5dac-ae10-785696cc7dec', // https://localhost
+            'app-a6263561-6a84-5d52-9891-02956f9fac65', // https://127.0.0.1
+            'app-26149f0b-8304-5228-b995-772dadcf410e', // http://localhost
+            'app-c2e27728-66d9-54dd-87cd-6f4e9b92e3e3', // http://127.0.0.1
+        ],
+        permissions: {
+            'driver:helloworld:greet': {},
+            'driver:puter-ocr:recognize': {},
+            'driver:puter-kvstore:get': {},
+            'driver:puter-kvstore:set': {},
+            'driver:puter-kvstore:del': {},
+            'driver:puter-kvstore:list': {},
+            'driver:puter-kvstore:flush': {},
+        },
+    },
+];
+
+module.exports = {
+    implicit_user_app_permissions,
+    default_implicit_user_app_permissions,
+};

+ 24 - 64
src/backend/src/services/auth/PermissionService.js

@@ -16,6 +16,11 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
+const {
+    implicit_user_app_permissions,
+    default_implicit_user_app_permissions
+} = require("../../data/hardcoded-permissions");
+
 const { get_user, get_app } = require("../../helpers");
 const { AssignableMethodsFeature } = require("../../traits/AssignableMethodsFeature");
 const { Context } = require("../../util/context");
@@ -23,70 +28,6 @@ const BaseService = require("../BaseService");
 const { DB_WRITE } = require("../database/consts");
 const { UserActorType, Actor, AppUnderUserActorType, AccessTokenActorType, SiteActorType } = require("./Actor");
 
-const default_implicit_user_app_permissions = {
-    'driver:helloworld:greet': {},
-    'driver:puter-kvstore': {},
-    'driver:puter-ocr:recognize': {},
-    'driver:puter-chat-completion': {},
-    'driver:puter-image-generation': {},
-    'driver:puter-tts': {},
-    'driver:puter-apps': {},
-    'driver:puter-subdomains': {},
-    'driver:temp-email': {},
-};
-
-const implicit_user_app_permissions = [
-    {
-        id: 'builtin-apps',
-        apps: [
-            'app-0bef044f-918f-4cbf-a0c0-b4a17ee81085', // about
-            'app-838dfbc4-bf8b-48c2-b47b-c4adc77fab58', // editor
-            'app-58282b08-990a-4906-95f7-fa37ff92452b', // draw
-            'app-0087b701-da09-4f49-a37d-2d6bcabc81ee', // minipaint
-            'app-3fea7529-266e-47d9-8776-31649cd06557', // terminal
-            'app-5584fbf7-ed69-41fc-99cd-85da21b1ef51', // camera
-            'app-7bdca1a4-6373-4c98-ad97-03ff2d608ca1', // recorder
-            'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77', // dev-center
-            'app-a2ae72a4-1ba3-4a29-b5c0-6de1be5cf178', // app-center
-            'app-74378e84-b9cd-5910-bcb1-3c50fa96d6e7', // https://nj.puter.site
-            'app-13a38aeb-f9f6-54f0-9bd3-9d4dd655ccfe', // https://cdpn.io
-            'app-dce8f797-82b0-5d95-a2f8-ebe4d71b9c54', // https://null.jsbin.com
-            'app-93005ce0-80d1-50d9-9b1e-9c453c375d56', // https://markus.puter.com
-        ],
-        permissions: {
-            'driver:helloworld:greet': {},
-            'driver:puter-ocr:recognize': {},
-            'driver:puter-kvstore:get': {},
-            'driver:puter-kvstore:set': {},
-            'driver:puter-kvstore:del': {},
-            'driver:puter-kvstore:list': {},
-            'driver:puter-kvstore:flush': {},
-            'driver:puter-chat-completion:complete': {},
-            'driver:puter-image-generation:generate': {},
-            'driver:puter-analytics:create_trace': {},
-            'driver:puter-analytics:record': {},
-        },
-    },
-    {
-        id: 'local-testing',
-        apps: [
-            'app-a392f3e5-35ca-5dac-ae10-785696cc7dec', // https://localhost
-            'app-a6263561-6a84-5d52-9891-02956f9fac65', // https://127.0.0.1
-            'app-26149f0b-8304-5228-b995-772dadcf410e', // http://localhost
-            'app-c2e27728-66d9-54dd-87cd-6f4e9b92e3e3', // http://127.0.0.1
-        ],
-        permissions: {
-            'driver:helloworld:greet': {},
-            'driver:puter-ocr:recognize': {},
-            'driver:puter-kvstore:get': {},
-            'driver:puter-kvstore:set': {},
-            'driver:puter-kvstore:del': {},
-            'driver:puter-kvstore:list': {},
-            'driver:puter-kvstore:flush': {},
-        },
-    },
-];
-
 const implicit_user_permissions = {
     // 'driver': {},
 };
@@ -895,6 +836,25 @@ class PermissionService extends BaseService {
                         }),
                     })
 
+                    const reading = await this.scan(actor, permission);
+                    const util = require('node:util');
+                    ctx.log(JSON.stringify(reading, undefined, '  '));
+                }
+            },
+            {
+                id: 'scan-app',
+                handler: async (args, ctx) => {
+                    const [ username, app_name, permission ] = args;
+                    const app = await get_app({ name: app_name });
+
+                    // actor from username
+                    const actor = new Actor({
+                        type: new AppUnderUserActorType({
+                            app,
+                            user: await get_user({ username }),
+                        }),
+                    })
+
                     const reading = await this.scan(actor, permission);
                     const util = require('node:util');
                     ctx.log(JSON.stringify(reading, undefined, '  '));

+ 3 - 0
src/backend/src/structured/sequence/scan-user-permission.js

@@ -25,6 +25,9 @@ module.exports = new Sequence([
     async function grant_if_system (a) {
         const reading = a.get('reading');
         const { actor } = a.values();
+        if ( !(actor.type instanceof UserActorType)  ) {
+            return;
+        }
         if ( actor.type.user.username === 'system' ) {
             reading.push({
                 $: 'option',

+ 84 - 6
src/backend/src/unstructured/permission-scanners.js

@@ -1,5 +1,9 @@
+const {
+    default_implicit_user_app_permissions,
+    implicit_user_app_permissions,
+} = require("../data/hardcoded-permissions");
 const { get_user } = require("../helpers");
-const { Actor, UserActorType } = require("../services/auth/Actor");
+const { Actor, UserActorType, AppUnderUserActorType } = require("../services/auth/Actor");
 
 const PERMISSION_SCANNERS = [
     {
@@ -21,6 +25,7 @@ const PERMISSION_SCANNERS = [
                     reading.push({
                         $: 'option',
                         source: 'implied',
+                        by: `implicator:${implicator.id}`,
                         data: implied,
                     });
                 }
@@ -30,9 +35,11 @@ const PERMISSION_SCANNERS = [
     {
         name: 'user-user',
         async scan (a) {
-            const reading = a.get('reading');
+            const { reading, actor, permission_options } = a.values();
+            if ( !(actor.type instanceof UserActorType)  ) {
+                return;
+            }
             const db = a.iget('db');
-            const { actor, permission_options } = a.values();
             
             let sql_perm = permission_options.map(perm => {
                 return `\`permission\` = ?`
@@ -77,8 +84,10 @@ const PERMISSION_SCANNERS = [
     {
         name: 'user-group-user',
         async scan (a) {
-            const reading = a.get('reading');
-            const { actor, permission_options } = a.values();
+            const { reading, actor, permission_options } = a.values();
+            if ( !(actor.type instanceof UserActorType)  ) {
+                return;
+            }
             const db = a.iget('db');
 
             let sql_perm = permission_options.map((perm) =>
@@ -116,7 +125,76 @@ const PERMISSION_SCANNERS = [
                 });
             }
         }
-    }
+    },
+    {
+        name: 'user-app',
+        async scan (a) {
+            const { reading, actor, permission_options } = a.values();
+            if ( !(actor.type instanceof AppUnderUserActorType)  ) {
+                return;
+            }
+            const db = a.iget('db');
+            
+            const app_uid = actor.type.app.uid;
+            
+            for ( const permission of permission_options ) {
+                {
+                    const implied = default_implicit_user_app_permissions[permission];
+                    if ( implied ) {
+                        reading.push({
+                            $: 'option',
+                            source: 'implied',
+                            by: 'user-app-hc-1',
+                            data: implied,
+                        });
+                    }
+                } {
+                    const implicit_permissions = {};
+                    for ( const implicit_permission of implicit_user_app_permissions ) {
+                        if ( implicit_permission.apps.includes(app_uid) ) {
+                            implicit_permissions[permission] = implicit_permission.permissions[permission];
+                        }
+                    }
+                    if ( implicit_permissions[permission] ) {
+                        reading.push({
+                            $: 'option',
+                            source: 'implied',
+                            by: 'user-app-hc-2',
+                            data: implicit_permissions[permission],
+                        });
+                    }
+                }
+            }
+
+            let sql_perm = permission_options.map(() =>
+                `\`permission\` = ?`).join(' OR ');
+            if ( permission_options.length > 1 ) sql_perm = '(' + sql_perm + ')';
+
+            // SELECT permission
+            const rows = await db.read(
+                'SELECT * FROM `user_to_app_permissions` ' +
+                'WHERE `user_id` = ? AND `app_id` = ? AND ' +
+                sql_perm,
+                [
+                    actor.type.user.id,
+                    actor.type.app.id,
+                    ...permission_options,
+                ]
+            );
+            
+            if ( rows[0] ) {
+                const row = rows[0];
+                const issuer_actor = actor.get_related_actor(UserActorType);
+                const issuer_reading = await a.icall('scan', issuer_actor, row.permission);
+                reading.push({
+                    $: 'path',
+                    via: 'user-app',
+                    issuer_username: actor.type.user.username,
+                    reading: issuer_reading,
+                });
+            }
+        }
+    },
 ];
 
 module.exports = {