Source Code

;; genome-access-control - Clarity 4
;; Fine-grained access control for genomic data

(define-constant ERR-NOT-AUTHORIZED (err u100))
(define-constant ERR-PERMISSION-NOT-FOUND (err u101))
(define-constant ERR-PERMISSION-EXPIRED (err u102))
(define-constant ERR-INVALID-ROLE (err u103))

(define-map permissions { resource-id: uint, requester: principal }
  {
    granted-by: principal,
    access-level: (string-ascii 20),
    granted-at: uint,
    expires-at: uint,
    scope: (string-ascii 50),
    is-active: bool
  }
)

(define-map access-roles uint
  {
    role-name: (string-ascii 50),
    role-description: (string-utf8 200),
    permissions-list: (list 20 (string-ascii 50)),
    created-at: uint,
    is-active: bool
  }
)

(define-map role-assignments { user: principal, resource-id: uint }
  {
    role-id: uint,
    assigned-by: principal,
    assigned-at: uint,
    expires-at: (optional uint),
    is-active: bool
  }
)

(define-map access-requests uint
  {
    requester: principal,
    resource-id: uint,
    requested-access-level: (string-ascii 20),
    justification: (string-utf8 500),
    requested-at: uint,
    status: (string-ascii 20),
    reviewed-by: (optional principal),
    reviewed-at: (optional uint)
  }
)

(define-map access-logs uint
  {
    user: principal,
    resource-id: uint,
    action: (string-ascii 50),
    access-level: (string-ascii 20),
    timestamp: uint,
    ip-hash: (optional (buff 32)),
    success: bool
  }
)

(define-map delegation-rules uint
  {
    delegator: principal,
    delegate: principal,
    resource-pattern: (string-ascii 100),
    permissions-delegated: (list 10 (string-ascii 50)),
    start-date: uint,
    end-date: uint,
    is-revocable: bool
  }
)

(define-data-var role-counter uint u0)
(define-data-var request-counter uint u0)
(define-data-var log-counter uint u0)
(define-data-var delegation-counter uint u0)

(define-public (grant-permission
    (resource-id uint)
    (grantee principal)
    (access-level (string-ascii 20))
    (expiration uint)
    (scope (string-ascii 50)))
  (begin
    (map-set permissions { resource-id: resource-id, requester: grantee }
      {
        granted-by: tx-sender,
        access-level: access-level,
        granted-at: stacks-block-time,
        expires-at: expiration,
        scope: scope,
        is-active: true
      })
    (ok true)))

(define-public (revoke-permission (resource-id uint) (grantee principal))
  (let ((permission (unwrap! (map-get? permissions { resource-id: resource-id, requester: grantee }) ERR-PERMISSION-NOT-FOUND)))
    (asserts! (is-eq tx-sender (get granted-by permission)) ERR-NOT-AUTHORIZED)
    (ok (map-set permissions { resource-id: resource-id, requester: grantee }
      (merge permission { is-active: false })))))

(define-public (create-access-role
    (role-name (string-ascii 50))
    (role-description (string-utf8 200))
    (permissions-list (list 20 (string-ascii 50))))
  (let ((role-id (+ (var-get role-counter) u1)))
    (map-set access-roles role-id
      {
        role-name: role-name,
        role-description: role-description,
        permissions-list: permissions-list,
        created-at: stacks-block-time,
        is-active: true
      })
    (var-set role-counter role-id)
    (ok role-id)))

(define-public (assign-role
    (user principal)
    (resource-id uint)
    (role-id uint)
    (expires-at (optional uint)))
  (begin
    (asserts! (is-some (map-get? access-roles role-id)) ERR-INVALID-ROLE)
    (map-set role-assignments { user: user, resource-id: resource-id }
      {
        role-id: role-id,
        assigned-by: tx-sender,
        assigned-at: stacks-block-time,
        expires-at: expires-at,
        is-active: true
      })
    (ok true)))

(define-public (request-access
    (resource-id uint)
    (requested-access-level (string-ascii 20))
    (justification (string-utf8 500)))
  (let ((request-id (+ (var-get request-counter) u1)))
    (map-set access-requests request-id
      {
        requester: tx-sender,
        resource-id: resource-id,
        requested-access-level: requested-access-level,
        justification: justification,
        requested-at: stacks-block-time,
        status: "pending",
        reviewed-by: none,
        reviewed-at: none
      })
    (var-set request-counter request-id)
    (ok request-id)))

(define-public (review-access-request
    (request-id uint)
    (approved bool))
  (let ((request (unwrap! (map-get? access-requests request-id) ERR-PERMISSION-NOT-FOUND)))
    (map-set access-requests request-id
      (merge request {
        status: (if approved "approved" "rejected"),
        reviewed-by: (some tx-sender),
        reviewed-at: (some stacks-block-time)
      }))
    (if approved
        (grant-permission
          (get resource-id request)
          (get requester request)
          (get requested-access-level request)
          (+ stacks-block-time u31536000)
          "full")
        (ok true))))

(define-public (log-access
    (resource-id uint)
    (action (string-ascii 50))
    (access-level (string-ascii 20))
    (ip-hash (optional (buff 32)))
    (success bool))
  (let ((log-id (+ (var-get log-counter) u1)))
    (map-set access-logs log-id
      {
        user: tx-sender,
        resource-id: resource-id,
        action: action,
        access-level: access-level,
        timestamp: stacks-block-time,
        ip-hash: ip-hash,
        success: success
      })
    (var-set log-counter log-id)
    (ok log-id)))

(define-public (delegate-access
    (delegate principal)
    (resource-pattern (string-ascii 100))
    (permissions-delegated (list 10 (string-ascii 50)))
    (duration uint)
    (is-revocable bool))
  (let ((delegation-id (+ (var-get delegation-counter) u1)))
    (map-set delegation-rules delegation-id
      {
        delegator: tx-sender,
        delegate: delegate,
        resource-pattern: resource-pattern,
        permissions-delegated: permissions-delegated,
        start-date: stacks-block-time,
        end-date: (+ stacks-block-time duration),
        is-revocable: is-revocable
      })
    (var-set delegation-counter delegation-id)
    (ok delegation-id)))

(define-read-only (check-permission (resource-id uint) (requester principal))
  (ok (map-get? permissions { resource-id: resource-id, requester: requester })))

(define-read-only (get-role (role-id uint))
  (ok (map-get? access-roles role-id)))

(define-read-only (get-role-assignment (user principal) (resource-id uint))
  (ok (map-get? role-assignments { user: user, resource-id: resource-id })))

(define-read-only (get-access-request (request-id uint))
  (ok (map-get? access-requests request-id)))

(define-read-only (get-access-log (log-id uint))
  (ok (map-get? access-logs log-id)))

(define-read-only (get-delegation (delegation-id uint))
  (ok (map-get? delegation-rules delegation-id)))

(define-read-only (is-permission-valid (resource-id uint) (requester principal))
  (let ((permission (map-get? permissions { resource-id: resource-id, requester: requester })))
    (ok (if (is-some permission)
            (let ((perm (unwrap-panic permission)))
              (and
                (get is-active perm)
                (> (get expires-at perm) stacks-block-time)))
            false))))

(define-read-only (validate-requester (requester principal))
  (principal-destruct? requester))

(define-read-only (format-resource-id (resource-id uint))
  (ok (int-to-ascii resource-id)))

(define-read-only (parse-resource-id (id-str (string-ascii 20)))
  (string-to-uint? id-str))

(define-read-only (get-bitcoin-block)
  (ok burn-block-height))

Functions (19)

FunctionAccessArgs
grant-permissionpublicresource-id: uint, grantee: principal, access-level: (string-ascii 20
revoke-permissionpublicresource-id: uint, grantee: principal
create-access-rolepublicrole-name: (string-ascii 50
assign-rolepublicuser: principal, resource-id: uint, role-id: uint, expires-at: (optional uint
request-accesspublicresource-id: uint, requested-access-level: (string-ascii 20
review-access-requestpublicrequest-id: uint, approved: bool
log-accesspublicresource-id: uint, action: (string-ascii 50
delegate-accesspublicdelegate: principal, resource-pattern: (string-ascii 100
check-permissionread-onlyresource-id: uint, requester: principal
get-roleread-onlyrole-id: uint
get-role-assignmentread-onlyuser: principal, resource-id: uint
get-access-requestread-onlyrequest-id: uint
get-access-logread-onlylog-id: uint
get-delegationread-onlydelegation-id: uint
is-permission-validread-onlyresource-id: uint, requester: principal
validate-requesterread-onlyrequester: principal
format-resource-idread-onlyresource-id: uint
parse-resource-idread-onlyid-str: (string-ascii 20
get-bitcoin-blockread-only