Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bob #1

Merged
merged 10 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@
"undernames",
"Undernames",
"UNDERNAMES"
]
],
"Lua.workspace.library": ["${addons}/ao/module/library"],
"Lua.workspace.checkThirdParty": true,
"[lua]": {
"editor.defaultFormatter": "JohnnyMorganz.stylua",
"editor.formatOnSave": true
}
}
118 changes: 118 additions & 0 deletions diagrams/process_interactions.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<mxfile host="65bd71144e">
<diagram id="UNxlQoblxGK7H0KAt1_N" name="Page-1">
<mxGraphModel dx="1616" dy="543" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="8" style="edgeStyle=none;html=1;fontSize=24;" edge="1" parent="1" source="2" target="7">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="2" value="Secretorium&lt;br&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
<mxGeometry x="150" y="250" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="3" value="KV" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
<mxGeometry x="370" y="540" width="60" height="80" as="geometry"/>
</mxCell>
<mxCell id="5" style="edgeStyle=none;html=1;" edge="1" parent="1" source="4" target="2">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="4" value="Dummy&lt;br&gt;" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
<mxGeometry x="-30" y="320" width="150" height="250" as="geometry"/>
</mxCell>
<mxCell id="6" value="&lt;font style=&quot;font-size: 24px;&quot;&gt;Spawn Vault&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="170" y="150" width="270" height="80" as="geometry"/>
</mxCell>
<mxCell id="11" style="edgeStyle=none;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;fontSize=14;" edge="1" parent="1" source="7" target="3">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="7" value="KV - Registry" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="360" y="370" width="230" height="80" as="geometry"/>
</mxCell>
<mxCell id="9" value="&lt;font style=&quot;font-size: 14px;&quot;&gt;KV-Registry.Spawn-KV-Store&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=24;" vertex="1" parent="1">
<mxGeometry x="310" y="280" width="210" height="40" as="geometry"/>
</mxCell>
<mxCell id="21" style="edgeStyle=none;html=1;fontSize=14;" edge="1" parent="1" source="13" target="14">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="13" value="Secretorium&lt;br&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
<mxGeometry x="140" y="770" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="14" value="KV" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
<mxGeometry x="365" y="910" width="60" height="80" as="geometry"/>
</mxCell>
<mxCell id="15" style="edgeStyle=none;html=1;" edge="1" parent="1" source="16" target="13">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="16" value="Dummy&lt;br&gt;" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
<mxGeometry x="-40" y="840" width="150" height="250" as="geometry"/>
</mxCell>
<mxCell id="17" value="&lt;font style=&quot;font-size: 24px;&quot;&gt;Set Secret&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="160" y="670" width="270" height="80" as="geometry"/>
</mxCell>
<mxCell id="22" value="&lt;h1&gt;Set&lt;/h1&gt;&lt;p&gt;Sets the initial public share and collaborator config for owner&lt;/p&gt;" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;fontSize=14;" vertex="1" parent="1">
<mxGeometry x="310" y="760" width="190" height="120" as="geometry"/>
</mxCell>
<mxCell id="23" style="edgeStyle=none;html=1;fontSize=14;" edge="1" parent="1" source="24" target="25">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="24" value="Secretorium&lt;br&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
<mxGeometry x="140" y="1210" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="48" style="edgeStyle=none;html=1;fontSize=14;" edge="1" parent="1" source="25" target="30">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="25" value="KV" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
<mxGeometry x="365" y="1350" width="60" height="80" as="geometry"/>
</mxCell>
<mxCell id="26" style="edgeStyle=none;html=1;" edge="1" parent="1" source="27" target="24">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="27" value="Dummy&lt;br&gt;" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
<mxGeometry x="-40" y="1280" width="150" height="250" as="geometry"/>
</mxCell>
<mxCell id="28" value="&lt;h1&gt;Request Authorization&lt;/h1&gt;&lt;p&gt;Other user requests access to &amp;lt;secret-name&amp;gt;.collaborators.&amp;lt;their address&amp;gt; to set their signature config&lt;/p&gt;" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;fontSize=14;" vertex="1" parent="1">
<mxGeometry x="310" y="1200" width="310" height="150" as="geometry"/>
</mxCell>
<mxCell id="29" style="edgeStyle=none;html=1;fontSize=14;" edge="1" parent="1" source="30" target="31">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="30" value="Secretorium&lt;br&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
<mxGeometry x="100" y="1650" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="47" style="edgeStyle=none;html=1;fontSize=14;" edge="1" parent="1" source="31" target="45">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="31" value="KV" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
<mxGeometry x="325" y="1790" width="60" height="80" as="geometry"/>
</mxCell>
<mxCell id="32" style="edgeStyle=none;html=1;" edge="1" parent="1" source="33" target="30">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="33" value="Dummy&lt;br&gt;" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
<mxGeometry x="-80" y="1720" width="150" height="250" as="geometry"/>
</mxCell>
<mxCell id="34" value="&lt;h1&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;Authorize&lt;/span&gt;&lt;/h1&gt;&lt;h1&gt;&lt;span style=&quot;background-color: initial; font-size: 14px; font-weight: normal;&quot;&gt;Owner authorizes collaborator&lt;/span&gt;&lt;br&gt;&lt;/h1&gt;" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;fontSize=14;" vertex="1" parent="1">
<mxGeometry x="270" y="1640" width="310" height="120" as="geometry"/>
</mxCell>
<mxCell id="41" style="edgeStyle=none;html=1;fontSize=14;" edge="1" parent="1" source="42" target="43">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="42" value="Secretorium&lt;br&gt;" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
<mxGeometry x="760" y="1360" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="43" value="KV" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
<mxGeometry x="985" y="1500" width="60" height="80" as="geometry"/>
</mxCell>
<mxCell id="44" style="edgeStyle=none;html=1;" edge="1" parent="1" source="45" target="42">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="45" value="Collaborator" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
<mxGeometry x="580" y="1430" width="150" height="250" as="geometry"/>
</mxCell>
<mxCell id="46" value="&lt;h1&gt;&lt;span style=&quot;background-color: initial;&quot;&gt;Set Config&lt;/span&gt;&lt;/h1&gt;&lt;h1&gt;&lt;span style=&quot;background-color: initial; font-size: 14px; font-weight: normal;&quot;&gt;Sets their signature config with chain config and encryption public key&lt;/span&gt;&lt;br&gt;&lt;/h1&gt;" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;fontSize=14;" vertex="1" parent="1">
<mxGeometry x="930" y="1350" width="310" height="150" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
"format": "prettier --write .",
"preview": "vite preview",
"prepare": "husky install",
"postinstall": "husky install"
"postinstall": "husky install",
"kv-registry:build": "node processes/tools/bundle-aos.js --path=\"./processes/kv_registry_init.lua\" --output=\"./processes/dist/kv_registry/aos-bundled.lua\"",
"kv-store:build": "node processes/tools/bundle-aos.js --path=\"./processes/kv_store_init.lua\" --output=\"./processes/dist/kv_store/aos-bundled.lua\"",
"aos:build": "yarn kv-registry:build && yarn kv-store:build",
"aos:publish": "node processes/tools/bundle-aos.js && node tools/publish-aos.js",
"aos:test": "node --test --test-concurrency 1 --experimental-wasm-memory64 processes/tests/*.test.js"
},
"dependencies": {
"@dha-team/arbundles": "^1.0.1",
Expand All @@ -36,6 +41,7 @@
"@babel/preset-typescript": "^7.18.6",
"@commitlint/cli": "^17.6.7",
"@commitlint/config-conventional": "^17.6.7",
"@permaweb/ao-loader": "^0.0.43",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "^14.1.2",
"@testing-library/user-event": "^14.5.1",
Expand Down
101 changes: 101 additions & 0 deletions processes/acl.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
--- ACL module for role-based and path-specific access control.
-- This module allows defining roles, assigning roles to users, checking permissions,
-- and handling authorization requests with support for path-based permissions.
-- @module acl

local acl = {}

--- Table of defined roles and their permissions.
-- Each role has an associated table of permissions, where permissions may be path-specific.
acl.roles = {}

--- Table of users and their assigned roles.
-- Each user has an associated table of roles they belong to.
acl.users = {}

--- Table of pending authorization requests by user.
-- Each user can have one pending authorization request at a time.
acl.authorizationRequests = {} -- Store pending authorization requests by user

--- Define a new role with a set of permissions.
---@param role string The name of the role to define.
---@param permissions table A table of permissions associated with the role.
-- Each permission can either be a boolean (true for global access on that action) or a table of path patterns.
-- For path-specific permissions, use a table with patterns that define the paths on which the role has access.
-- For example, a role with `{ ["KV-Store.Set"] = { "data.entries", "config.settings" } }` can only modify these paths.
function acl.defineRole(role, permissions)
acl.roles[role] = permissions or {}
end

--- Assign a role to a user.
---@param user string The identifier for the user.
---@param role string The role to assign to the user.
---@raise Error if the role is not defined.
function acl.assignRole(user, role)
if not acl.roles[role] then
error("Role '" .. role .. "' is not defined")
end
acl.users[user] = acl.users[user] or {}
acl.users[user][role] = true
end

--- Check if a user has permission for a specific action and path.
---@param user string The identifier for the user.
---@param action string The action the user wishes to perform.
---@param path string The specific path being accessed or modified.
---@return boolean True if the user has permission for the action and path, otherwise false.
---@details Each action’s permission can be `true` for global access or a table of paths for restricted access.
-- For example, `permissions = { ["KV-Store.Set"] = { "config.settings", "data.entries" } }`
-- allows modifying only `config.settings` and `data.entries`.
function acl.hasPermission(user, action, path)
local userRoles = acl.users[user]
if not userRoles then
return false
end

for role in pairs(userRoles) do
local rolePermissions = acl.roles[role]
if rolePermissions then
local actionPermissions = rolePermissions[action]
if actionPermissions then
-- Global permission if set to `true`
if actionPermissions == true then
return true
end
-- If actionPermissions is a table, treat each entry as a path pattern
if type(actionPermissions) == "table" then
for _, pattern in ipairs(actionPermissions) do
if path:match(pattern) then
return true -- Path matches, permission granted
end
end
end
end
end
end
return false -- No matching permissions found
end

--- Store a user's authorization request.
-- This replaces any existing request for the user.
---@param user string The identifier for the user.
---@param role string The role the user is requesting.
---@param permissions table A table of actions and corresponding permissions being requested.
function acl.storeAuthorizationRequest(user, role, permissions)
acl.authorizationRequests[user] = { role = role, permissions = permissions }
end

--- Retrieve a user's current authorization request.
---@param user string The identifier for the user.
---@return table The user's authorization request, containing the requested role, paths, and permissions, or nil if no request exists.
function acl.getAuthorizationRequest(user)
return acl.authorizationRequests[user]
end

--- Clear a user's authorization request after processing.
---@param user string The identifier for the user.
function acl.clearAuthorizationRequest(user)
acl.authorizationRequests[user] = nil
end

return acl
Loading
Loading