feat: create system roles
This commit is contained in:
152
internal/repository/roles.sql.go
Normal file
152
internal/repository/roles.sql.go
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.29.0
|
||||||
|
// source: roles.sql
|
||||||
|
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const addPermissionsToRoleByKey = `-- name: AddPermissionsToRoleByKey :exec
|
||||||
|
INSERT INTO role_permissions (role_id, permission_id)
|
||||||
|
SELECT
|
||||||
|
$1,
|
||||||
|
p.id
|
||||||
|
FROM
|
||||||
|
permissions p
|
||||||
|
JOIN
|
||||||
|
unnest($2::text[]) AS key_str
|
||||||
|
ON key_str = p.scope || '_' || p.name
|
||||||
|
`
|
||||||
|
|
||||||
|
type AddPermissionsToRoleByKeyParams struct {
|
||||||
|
RoleID uuid.UUID `json:"role_id"`
|
||||||
|
PermissionKeys []string `json:"permission_keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) AddPermissionsToRoleByKey(ctx context.Context, arg AddPermissionsToRoleByKeyParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, addPermissionsToRoleByKey, arg.RoleID, arg.PermissionKeys)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const createRole = `-- name: CreateRole :one
|
||||||
|
INSERT INTO roles (name, scope, description)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
RETURNING id, name, scope, description
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateRoleParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
Description *string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateRole(ctx context.Context, arg CreateRoleParams) (Role, error) {
|
||||||
|
row := q.db.QueryRow(ctx, createRole, arg.Name, arg.Scope, arg.Description)
|
||||||
|
var i Role
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Description,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const findRole = `-- name: FindRole :one
|
||||||
|
SELECT id, name, scope, description
|
||||||
|
FROM roles
|
||||||
|
WHERE scope = $1 AND name = $2
|
||||||
|
`
|
||||||
|
|
||||||
|
type FindRoleParams struct {
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) FindRole(ctx context.Context, arg FindRoleParams) (Role, error) {
|
||||||
|
row := q.db.QueryRow(ctx, findRole, arg.Scope, arg.Name)
|
||||||
|
var i Role
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Scope,
|
||||||
|
&i.Description,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRolesGroupedWithPermissions = `-- name: GetRolesGroupedWithPermissions :many
|
||||||
|
SELECT
|
||||||
|
r.scope,
|
||||||
|
json_agg (
|
||||||
|
json_build_object (
|
||||||
|
'id',
|
||||||
|
r.id,
|
||||||
|
'name',
|
||||||
|
r.name,
|
||||||
|
'description',
|
||||||
|
r.description,
|
||||||
|
'permissions',
|
||||||
|
COALESCE(p_list.permissions, '[]')
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
r.name
|
||||||
|
) AS roles
|
||||||
|
FROM
|
||||||
|
roles r
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
rp.role_id,
|
||||||
|
json_agg (
|
||||||
|
json_build_object (
|
||||||
|
'id',
|
||||||
|
p.id,
|
||||||
|
'name',
|
||||||
|
p.name,
|
||||||
|
'scope',
|
||||||
|
p.scope,
|
||||||
|
'description',
|
||||||
|
p.description
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
p.name
|
||||||
|
) AS permissions
|
||||||
|
FROM
|
||||||
|
role_permissions rp
|
||||||
|
JOIN permissions p ON p.id = rp.permission_id
|
||||||
|
GROUP BY
|
||||||
|
rp.role_id
|
||||||
|
) p_list ON p_list.role_id = r.id
|
||||||
|
GROUP BY
|
||||||
|
r.scope
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetRolesGroupedWithPermissionsRow struct {
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
Roles []byte `json:"roles"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetRolesGroupedWithPermissions(ctx context.Context) ([]GetRolesGroupedWithPermissionsRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, getRolesGroupedWithPermissions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetRolesGroupedWithPermissionsRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetRolesGroupedWithPermissionsRow
|
||||||
|
if err := rows.Scan(&i.Scope, &i.Roles); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
@ -2,6 +2,7 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"gitea.local/admin/hspguard/internal/repository"
|
"gitea.local/admin/hspguard/internal/repository"
|
||||||
@ -11,6 +12,11 @@ func String(s string) *string {
|
|||||||
return &s
|
return &s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RolePermissions struct {
|
||||||
|
Permissions []string `json:"permissions"`
|
||||||
|
repository.Role
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
SYSTEM_SCOPE string = "system"
|
SYSTEM_SCOPE string = "system"
|
||||||
SYSTEM_PERMISSIONS []repository.Permission = []repository.Permission{
|
SYSTEM_PERMISSIONS []repository.Permission = []repository.Permission{
|
||||||
@ -46,6 +52,111 @@ var (
|
|||||||
Name: "revoke_sessions",
|
Name: "revoke_sessions",
|
||||||
Description: String("Allow users to revoke their active sessions"),
|
Description: String("Allow users to revoke their active sessions"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "view_api_services",
|
||||||
|
Description: String("Allow users to view API Services (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add_api_services",
|
||||||
|
Description: String("Allow users to register new API Services (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "edit_api_services",
|
||||||
|
Description: String("Allow users to edit API Services (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove_api_services",
|
||||||
|
Description: String("Allow users to remove API Services (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "view_users",
|
||||||
|
Description: String("Allow users to view other users (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add_users",
|
||||||
|
Description: String("Allow users to create new users (for admin)"),
|
||||||
|
},
|
||||||
|
// TODO: block, delete users
|
||||||
|
{
|
||||||
|
Name: "view_user_sessions",
|
||||||
|
Description: String("Allow users to view user sessions (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "revoke_user_sessions",
|
||||||
|
Description: String("Allow users to revoke user sessions (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "view_service_sessions",
|
||||||
|
Description: String("Allow users to view service sessions (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "revoke_service_sessions",
|
||||||
|
Description: String("Allow users to revoke service sessions (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "view_permissions",
|
||||||
|
Description: String("Allow users to view all permissions (for admin)"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "view_roles_groups",
|
||||||
|
Description: String("Allow users to view roles & groups (for admin)"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
SYSTEM_ROLES []RolePermissions = []RolePermissions{
|
||||||
|
{
|
||||||
|
Permissions: []string{
|
||||||
|
"system_log_into_guard",
|
||||||
|
"system_register",
|
||||||
|
"system_edit_profile",
|
||||||
|
"system_recover_credentials",
|
||||||
|
"system_verify_profile",
|
||||||
|
"system_access_home_services",
|
||||||
|
"system_view_sessions",
|
||||||
|
"system_revoke_sessions",
|
||||||
|
"system_view_api_services",
|
||||||
|
"system_add_api_services",
|
||||||
|
"system_edit_api_services",
|
||||||
|
"system_remove_api_services",
|
||||||
|
"system_view_users",
|
||||||
|
"system_add_users",
|
||||||
|
"system_view_user_sessions",
|
||||||
|
"system_revoke_user_sessions",
|
||||||
|
"system_view_service_sessions",
|
||||||
|
"system_revoke_service_sessions",
|
||||||
|
"system_view_permissions",
|
||||||
|
"system_view_roles_groups",
|
||||||
|
},
|
||||||
|
Role: repository.Role{
|
||||||
|
Name: "admin",
|
||||||
|
Description: String("User with full power"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Permissions: []string{
|
||||||
|
"system_log_into_guard",
|
||||||
|
"system_register",
|
||||||
|
"system_edit_profile",
|
||||||
|
"system_recover_credentials",
|
||||||
|
"system_verify_profile",
|
||||||
|
"system_access_home_services",
|
||||||
|
"system_view_sessions",
|
||||||
|
"system_revoke_sessions",
|
||||||
|
},
|
||||||
|
Role: repository.Role{
|
||||||
|
Name: "family_member",
|
||||||
|
Description: String("User that is able to use home services"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Permissions: []string{
|
||||||
|
"system_log_into_guard",
|
||||||
|
"system_register",
|
||||||
|
},
|
||||||
|
Role: repository.Role{
|
||||||
|
Name: "guest",
|
||||||
|
Description: String("New user that needs approve for everything from admin"),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -67,4 +178,35 @@ func EnsureSystemPermissions(ctx context.Context, repo *repository.Queries) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, role := range SYSTEM_ROLES {
|
||||||
|
found, err := repo.FindRole(ctx, repository.FindRoleParams{
|
||||||
|
Scope: SYSTEM_SCOPE,
|
||||||
|
Name: role.Name,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("INFO: Create new SYSTEM role '%s'\n", role.Name)
|
||||||
|
found, err = repo.CreateRole(ctx, repository.CreateRoleParams{
|
||||||
|
Name: role.Name,
|
||||||
|
Scope: SYSTEM_SCOPE,
|
||||||
|
Description: role.Description,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("ERR: Failed to create SYSTEM role '%s': %v\n", role.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var mappedPerms []string
|
||||||
|
|
||||||
|
for _, perm := range role.Permissions {
|
||||||
|
mappedPerms = append(mappedPerms, fmt.Sprintf("%s_%s", SYSTEM_SCOPE, perm))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := repo.AddPermissionsToRoleByKey(ctx, repository.AddPermissionsToRoleByKeyParams{
|
||||||
|
RoleID: found.ID,
|
||||||
|
PermissionKeys: mappedPerms,
|
||||||
|
}); err != nil {
|
||||||
|
log.Fatalf("ERR: Failed to assign required permissions to SYSTEM role %s: %v\n", found.Name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
65
queries/roles.sql
Normal file
65
queries/roles.sql
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
-- name: FindRole :one
|
||||||
|
SELECT *
|
||||||
|
FROM roles
|
||||||
|
WHERE scope = $1 AND name = $2;
|
||||||
|
|
||||||
|
-- name: GetRolesGroupedWithPermissions :many
|
||||||
|
SELECT
|
||||||
|
r.scope,
|
||||||
|
json_agg (
|
||||||
|
json_build_object (
|
||||||
|
'id',
|
||||||
|
r.id,
|
||||||
|
'name',
|
||||||
|
r.name,
|
||||||
|
'description',
|
||||||
|
r.description,
|
||||||
|
'permissions',
|
||||||
|
COALESCE(p_list.permissions, '[]')
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
r.name
|
||||||
|
) AS roles
|
||||||
|
FROM
|
||||||
|
roles r
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
rp.role_id,
|
||||||
|
json_agg (
|
||||||
|
json_build_object (
|
||||||
|
'id',
|
||||||
|
p.id,
|
||||||
|
'name',
|
||||||
|
p.name,
|
||||||
|
'scope',
|
||||||
|
p.scope,
|
||||||
|
'description',
|
||||||
|
p.description
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
p.name
|
||||||
|
) AS permissions
|
||||||
|
FROM
|
||||||
|
role_permissions rp
|
||||||
|
JOIN permissions p ON p.id = rp.permission_id
|
||||||
|
GROUP BY
|
||||||
|
rp.role_id
|
||||||
|
) p_list ON p_list.role_id = r.id
|
||||||
|
GROUP BY
|
||||||
|
r.scope;
|
||||||
|
|
||||||
|
-- name: CreateRole :one
|
||||||
|
INSERT INTO roles (name, scope, description)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
|
-- name: AddPermissionsToRoleByKey :exec
|
||||||
|
INSERT INTO role_permissions (role_id, permission_id)
|
||||||
|
SELECT
|
||||||
|
sqlc.arg(role_id),
|
||||||
|
p.id
|
||||||
|
FROM
|
||||||
|
permissions p
|
||||||
|
JOIN
|
||||||
|
unnest(sqlc.arg(permission_keys)::text[]) AS key_str
|
||||||
|
ON key_str = p.scope || '_' || p.name;
|
Reference in New Issue
Block a user