@@ -35,6 +35,7 @@ export const DOWNLOAD_PACKAGE_ENDPOINT = (id: number) => `${PACKAGES_ENDPOINT}/$
3535
3636export const DEVICES_ENDPOINT = `${ SERVER_URL } /api/v2/devices` ;
3737export const PENDING_ENDPOINT = `${ SERVER_URL } /api/v1/auth/pending` ;
38+ export const PERMISSIONS_ENDPOINT = `${ SERVER_URL } /api/v1/permissions` ;
3839export const REGISTER_DEVICE_ENDPOINT = `${ SERVER_URL } /api/v1/auth/register` ;
3940
4041export const GROUPS_ENDPOINT = `${ SERVER_URL } /api/v2/groups` ;
@@ -49,6 +50,71 @@ export const LOGOUT_PATH = `${OIDC_LOGOUT_URL}?client_id=${OAUTH2_CLIENT}&post_l
4950
5051export const POLL_INTERVAL = 2500 ;
5152
53+ /**
54+ * RDFM roles specified in
55+ * https://antmicro.github.io/rdfm/rdfm_mgmt_server.html#basic-configuration
56+ */
57+ export enum AdminRole {
58+ RW = 'rdfm_admin_rw' ,
59+ RO = 'rdfm_admin_ro' ,
60+ UPLOAD_ROOTFS_IMAGE = 'rdfm_upload_rootfs_image' ,
61+ UPLOAD_SINGLE_FILE = 'rdfm_upload_single_file' ,
62+ }
63+
64+ /**
65+ * RDFM permissions specified in
66+ * https://antmicro.github.io/rdfm/rdfm_mgmt_server.html#permissions
67+ */
68+ export type Permission = {
69+ permission : 'read' | 'update' | 'delete' ;
70+ resource : 'package' | 'group' | 'device' ;
71+ resource_id : number ;
72+ user_id : string ;
73+ } ;
74+
75+ export const adminRoles = ref < AdminRole [ ] > ( [ ] ) ;
76+ export const permissions = ref < Permission [ ] > ( [ ] ) ;
77+
78+ export const hasPermission = (
79+ permission : Permission [ 'permission' ] ,
80+ resource : Permission [ 'resource' ] ,
81+ resource_id ?: number ,
82+ ) =>
83+ permissions . value . some (
84+ ( p ) => p . resource == resource && resource_id == p . resource_id && permission == p . permission ,
85+ ) ;
86+
87+ export const hasAdminRole = ( r : AdminRole ) => adminRoles . value . includes ( r ) ;
88+
89+ export const allowedTo = (
90+ permission : Permission [ 'permission' ] ,
91+ resource : Permission [ 'resource' ] ,
92+ id ?: number ,
93+ groups ?: Group [ ] ,
94+ ) => {
95+ if ( hasAdminRole ( AdminRole . RW ) || ( hasAdminRole ( AdminRole . RO ) && permission == 'read' ) ) {
96+ return true ;
97+ }
98+
99+ if ( hasPermission ( permission , resource , id ) ) {
100+ return true ;
101+ }
102+
103+ if ( id != null && groups ) {
104+ const hasGroupPermission = groups
105+ . filter (
106+ ( g ) =>
107+ ( resource == 'package' && g . packages . includes ( id ) ) ||
108+ ( resource == 'device' && g . devices . includes ( id ) ) ,
109+ )
110+ . some ( ( g ) => allowedTo ( permission , 'group' , g . id ) ) ;
111+
112+ return hasGroupPermission ;
113+ }
114+
115+ return false ;
116+ } ;
117+
52118/**
53119 * Package interface specified in
54120 * https://antmicro.github.io/rdfm/api.html#get--api-v1-packages-response-json-array-of-objects
@@ -125,35 +191,35 @@ export enum PollingStatus {
125191 ActivePolling ,
126192}
127193
194+ export const fetchWrapper = async (
195+ url : string ,
196+ method : string ,
197+ headers : Headers = new Headers ( ) ,
198+ body ?: BodyInit ,
199+ ) => {
200+ let response ;
201+ try {
202+ const accessToken = localStorage . getItem ( 'access_token' ) ;
203+
204+ if ( accessToken ) {
205+ headers . append ( 'Authorization' , `Bearer token=${ accessToken } ` ) ;
206+ }
207+ response = await fetch ( url , { method, body, headers : headers } ) ;
208+ if ( ! response . ok ) {
209+ throw new Error ( `Fetch returned status ${ response . status } ` ) ;
210+ }
211+ const data = await response . json ( ) ;
212+ return { success : true , code : response . status , data } ;
213+ } catch ( e ) {
214+ console . error ( `Failed to fetch ${ url } - ${ e } ` ) ;
215+ return { success : false , code : response ?. status , data : undefined } ;
216+ }
217+ } ;
218+
128219export const resourcesGetter = < T > ( resources_url : string ) => {
129220 const resources : Ref < T | undefined > = ref ( undefined ) ;
130221 const pollingStatus : Ref < PollingStatus > = ref ( PollingStatus . InitialPoll ) ;
131222
132- const fetchWrapper = async (
133- url : string ,
134- method : string ,
135- headers : Headers = new Headers ( ) ,
136- body ?: BodyInit ,
137- ) => {
138- let response ;
139- try {
140- const accessToken = localStorage . getItem ( 'access_token' ) ;
141-
142- if ( accessToken ) {
143- headers . append ( 'Authorization' , `Bearer token=${ accessToken } ` ) ;
144- }
145- response = await fetch ( url , { method, body, headers : headers } ) ;
146- if ( ! response . ok ) {
147- throw new Error ( `Fetch returned status ${ response . status } ` ) ;
148- }
149- const data = await response . json ( ) ;
150- return { success : true , code : response . status , data } ;
151- } catch ( e ) {
152- console . error ( `Failed to fetch ${ url } - ${ e } ` ) ;
153- return { success : false , code : response ?. status , data : undefined } ;
154- }
155- } ;
156-
157223 const fetchGET = ( url : string ) => fetchWrapper ( url , 'GET' ) ;
158224
159225 const fetchPOST = ( url : string , headers : Headers , body : BodyInit ) =>
0 commit comments