;; title: Stx-VerifyDocu
;; version:
;; summary:
;; description:
;; Document Verification Smart Contract
;; Enhanced version with improved security and validation
;; Error codes
(define-constant ERR-UNAUTHORIZED-ACCESS (err u100))
(define-constant ERR-DUPLICATE-DOCUMENT (err u101))
(define-constant ERR-DOCUMENT-MISSING (err u102))
(define-constant ERR-DOCUMENT-ALREADY-VERIFIED (err u103))
(define-constant ERR-INVALID-DOCUMENT-HASH-ID (err u104))
(define-constant ERR-INVALID-CONTENT-HASH (err u105))
(define-constant ERR-INVALID-METADATA (err u106))
(define-constant ERR-INVALID-AUTHORIZED-USER (err u107))
(define-constant ERR-INVALID-INPUT (err u108))
(define-constant ERR-PERMISSION-DENIED (err u109))
;; Constants for verification status
(define-constant STATUS-PENDING "PENDING")
(define-constant STATUS-VERIFIED "VERIFIED")
;; Define document record type
(define-data-var document-record-type {
document-owner: principal,
document-content-hash: (buff 32),
submission-timestamp: uint,
verification-status: (string-ascii 20),
verification-authority: (optional principal),
document-metadata: (string-utf8 256),
document-version: uint,
verification-complete: bool,
} {
document-owner: tx-sender,
document-content-hash: 0x0000000000000000000000000000000000000000000000000000000000000000,
submission-timestamp: u0,
verification-status: STATUS-PENDING,
verification-authority: none,
document-metadata: u"",
document-version: u0,
verification-complete: false,
})
;; Data maps
(define-map document-records
{ document-hash-id: (buff 32) }
{
document-owner: principal,
document-content-hash: (buff 32),
submission-timestamp: uint,
verification-status: (string-ascii 20),
verification-authority: (optional principal),
document-metadata: (string-utf8 256),
document-version: uint,
verification-complete: bool,
}
)
(define-map document-permissions
{
document-hash-id: (buff 32),
authorized-user: principal,
}
{
document-viewing-permission: bool,
document-verification-permission: bool,
}
)
;; Input validation functions
(define-private (check-buff-32 (input (buff 32)))
(if (is-eq (len input) u32)
(ok input)
ERR-INVALID-INPUT
)
)
(define-private (check-string-utf8 (input (string-utf8 256)))
(if (and
(<= (len input) u256)
(> (len input) u0)
)
(ok input)
ERR-INVALID-INPUT
)
)
(define-private (check-principal (input principal))
(if (not (is-eq input tx-sender))
(ok input)
ERR-INVALID-INPUT
)
)
;; Enhanced validation functions with consistent response types
(define-private (validate-and-sanitize-hash (hash (buff 32)))
(check-buff-32 hash)
)
(define-private (validate-and-sanitize-metadata (metadata (string-utf8 256)))
(check-string-utf8 metadata)
)
(define-private (validate-and-sanitize-user
(document-owner principal)
(authorized-user principal)
)
(if (not (is-eq document-owner authorized-user))
(ok authorized-user)
ERR-INVALID-AUTHORIZED-USER
)
)
;; Safe getter functions
(define-private (safe-get-document (document-hash-id (buff 32)))
(ok (unwrap! (map-get? document-records { document-hash-id: document-hash-id })
ERR-DOCUMENT-MISSING
))
)
;; Read-only functions
(define-read-only (get-document-details (document-hash-id (buff 32)))
(let ((validated-hash-id (try! (validate-and-sanitize-hash document-hash-id))))
(safe-get-document validated-hash-id)
)
)
(define-read-only (get-user-permissions
(document-hash-id (buff 32))
(authorized-user principal)
)
(let (
(validated-hash-id (try! (validate-and-sanitize-hash document-hash-id)))
(validated-user (try! (check-principal authorized-user)))
)
(ok (default-to {
document-viewing-permission: false,
document-verification-permission: false,
}
(map-get? document-permissions {
document-hash-id: validated-hash-id,
authorized-user: validated-user,
})
))
)
)
(define-public (modify-existing-document
(document-hash-id (buff 32))
(updated-content-hash (buff 32))
(updated-metadata (string-utf8 256))
)
(let (
(validated-hash-id (unwrap! (validate-and-sanitize-hash document-hash-id)
ERR-INVALID-DOCUMENT-HASH-ID
))
(validated-content-hash (unwrap! (validate-and-sanitize-hash updated-content-hash)
ERR-INVALID-CONTENT-HASH
))
(validated-metadata (unwrap! (validate-and-sanitize-metadata updated-metadata)
ERR-INVALID-METADATA
))
(existing-doc (unwrap! (safe-get-document validated-hash-id) ERR-DOCUMENT-MISSING))
)
(asserts! (is-eq (get document-owner existing-doc) tx-sender)
ERR-UNAUTHORIZED-ACCESS
)
(asserts! (not (get verification-complete existing-doc))
ERR-DOCUMENT-ALREADY-VERIFIED
)
(ok (map-set document-records { document-hash-id: validated-hash-id }
(merge existing-doc {
document-content-hash: validated-content-hash,
document-metadata: validated-metadata,
submission-timestamp: stacks-block-time,
document-version: (+ (get document-version existing-doc) u1),
verification-complete: false,
})
))
)
)
(define-public (perform-document-verification (document-hash-id (buff 32)))
(let (
(validated-hash-id (unwrap! (validate-and-sanitize-hash document-hash-id)
ERR-INVALID-DOCUMENT-HASH-ID
))
(existing-doc (unwrap! (safe-get-document validated-hash-id) ERR-DOCUMENT-MISSING))
(permissions (unwrap! (get-user-permissions validated-hash-id tx-sender)
ERR-PERMISSION-DENIED
))
)
(asserts! (get document-verification-permission permissions)
ERR-UNAUTHORIZED-ACCESS
)
(asserts! (not (get verification-complete existing-doc))
ERR-DOCUMENT-ALREADY-VERIFIED
)
(ok (map-set document-records { document-hash-id: validated-hash-id }
(merge existing-doc {
verification-status: STATUS-VERIFIED,
verification-authority: (some tx-sender),
verification-complete: true,
})
))
)
)
;; Public functions
(define-public (register-new-document
(document-hash-id (buff 32))
(document-content-hash (buff 32))
(document-metadata (string-utf8 256))
)
(let (
(document-submitter tx-sender)
(validated-hash-id (unwrap! (validate-and-sanitize-hash document-hash-id)
ERR-INVALID-DOCUMENT-HASH-ID
))
(validated-content-hash (unwrap! (validate-and-sanitize-hash document-content-hash)
ERR-INVALID-CONTENT-HASH
))
(validated-metadata (unwrap! (validate-and-sanitize-metadata document-metadata)
ERR-INVALID-METADATA
))
)
;; Check for duplicate document
(asserts!
(is-none (map-get? document-records { document-hash-id: validated-hash-id }))
ERR-DUPLICATE-DOCUMENT
)
(ok (map-set document-records { document-hash-id: validated-hash-id } {
document-owner: document-submitter,
document-content-hash: validated-content-hash,
submission-timestamp: stacks-block-time,
verification-status: STATUS-PENDING,
verification-authority: none,
document-metadata: validated-metadata,
document-version: u1,
verification-complete: false,
}))
)
)
(define-public (assign-document-permissions
(document-hash-id (buff 32))
(authorized-user principal)
(grant-viewing-permission bool)
(grant-verification-permission bool)
)
(let (
(validated-hash-id (unwrap! (validate-and-sanitize-hash document-hash-id)
ERR-INVALID-DOCUMENT-HASH-ID
))
(validated-user (unwrap! (check-principal authorized-user) ERR-INVALID-AUTHORIZED-USER))
(existing-doc (unwrap! (safe-get-document validated-hash-id) ERR-DOCUMENT-MISSING))
)
(asserts! (is-eq (get document-owner existing-doc) tx-sender)
ERR-UNAUTHORIZED-ACCESS
)
(ok (map-set document-permissions {
document-hash-id: validated-hash-id,
authorized-user: validated-user,
} {
document-viewing-permission: grant-viewing-permission,
document-verification-permission: grant-verification-permission,
}))
)
)
(define-public (remove-document-permissions
(document-hash-id (buff 32))
(authorized-user principal)
)
(let (
(validated-hash-id (unwrap! (validate-and-sanitize-hash document-hash-id)
ERR-INVALID-DOCUMENT-HASH-ID
))
(validated-user (unwrap! (check-principal authorized-user) ERR-INVALID-AUTHORIZED-USER))
(existing-doc (unwrap! (safe-get-document validated-hash-id) ERR-DOCUMENT-MISSING))
)
(asserts! (is-eq (get document-owner existing-doc) tx-sender)
ERR-UNAUTHORIZED-ACCESS
)
(ok (map-delete document-permissions {
document-hash-id: validated-hash-id,
authorized-user: validated-user,
}))
)
)