# πŸ” Ackify > **Proof of Read. Compliance made simple.** Secure document reading validation service with cryptographic traceability and irrefutable proof. [![Build](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/btouchard/ackify-ce) [![Security](https://img.shields.io/badge/crypto-Ed25519-blue.svg)](https://en.wikipedia.org/wiki/EdDSA) [![Go](https://img.shields.io/badge/go-1.24.5-blue.svg)](https://golang.org/) [![License](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](LICENSE) > πŸ‡«πŸ‡· [Version franΓ§aise disponible ici](README_FR.md) ### Visite our website here : https://www.ackify.eu ## 🎯 Why Ackify? **Problem**: How to prove that a collaborator has actually read and understood an important document? **Solution**: Ed25519 cryptographic signatures with immutable timestamps and complete traceability. ### Real-world use cases - βœ… Security policy validation - βœ… Mandatory training attestations - βœ… GDPR acknowledgment - βœ… Contractual acknowledgments - βœ… Quality and compliance procedures --- ## πŸ“Έ VidΓ©os Click to GIFs for open videos WebM in your browser.
1) Create sign
Initialisation d’une signature
2) User sign flow
Parcours de signature utilisateur
## πŸ“Έ Screenshots
Home page
Home page
Signing request
Signing request
Signature confirmed
Signature confirmed
Signatures list
Signatures list
Outline integration
Outline integration
Google Docs integration
Google Docs integration
--- ## ⚑ Quick Start ### With Docker (recommended) ```bash git clone https://github.com/btouchard/ackify-ce.git cd ackify-ce # Minimal configuration cp .env.example .env # Edit .env with your OAuth2 settings # Start docker compose up -d # Test curl http://localhost:8080/health # alias: /healthz ``` ### Required variables ```bash ACKIFY_BASE_URL="https://your-domain.com" ACKIFY_OAUTH_CLIENT_ID="your-oauth-client-id" # Google/GitHub/GitLab ACKIFY_OAUTH_CLIENT_SECRET="your-oauth-client-secret" ACKIFY_DB_DSN="postgres://user:password@localhost/ackify?sslmode=disable" ACKIFY_OAUTH_COOKIE_SECRET="$(openssl rand -base64 32)" ``` --- ## πŸš€ Simple Usage ### 1. Request a signature ``` https://your-domain.com/sign?doc=security_procedure_2025 ``` β†’ User authenticates via OAuth2 and validates their reading ### 2. Verify signatures ```bash # JSON API - Complete list curl "https://your-domain.com/status?doc=security_procedure_2025" # PNG Badge - Individual status curl "https://your-domain.com/status.png?doc=security_procedure_2025&user=john.doe@company.com" ``` ### 3. Integrate into your pages ```html ``` --- ## πŸ”§ OAuth2 Configuration ### Supported providers | Provider | Configuration | |----------|---------------| | **Google** | `ACKIFY_OAUTH_PROVIDER=google` | | **GitHub** | `ACKIFY_OAUTH_PROVIDER=github` | | **GitLab** | `ACKIFY_OAUTH_PROVIDER=gitlab` + `ACKIFY_OAUTH_GITLAB_URL` | | **Custom** | Custom endpoints | ### Custom provider ```bash # Leave ACKIFY_OAUTH_PROVIDER empty ACKIFY_OAUTH_AUTH_URL="https://auth.company.com/oauth/authorize" ACKIFY_OAUTH_TOKEN_URL="https://auth.company.com/oauth/token" ACKIFY_OAUTH_USERINFO_URL="https://auth.company.com/api/user" ACKIFY_OAUTH_SCOPES="read:user,user:email" ``` ### Domain restriction ```bash ACKIFY_OAUTH_ALLOWED_DOMAIN="@company.com" # Only @company.com emails ``` --- ## πŸ›‘οΈ Security & Architecture ### Cryptographic security - **Ed25519**: State-of-the-art digital signatures - **SHA-256**: Payload hashing against tampering - **Immutable timestamps**: PostgreSQL triggers - **Encrypted sessions**: Secure cookies - **CSP headers**: XSS protection ### Go architecture ``` cmd/ackapp/ # Entry point internal/ domain/ # Business logic models/ # Entities repositories/ # Persistence interfaces application/ # Use cases services/ # Business implementations infrastructure/ # Adapters auth/ # OAuth2 database/ # PostgreSQL config/ # Configuration presentation/ # HTTP handlers/ # Controllers + interfaces templates/ # HTML views pkg/ # Shared utilities ``` ### Technology stack - **Go 1.24.5**: Performance and simplicity - **PostgreSQL**: Integrity constraints - **OAuth2**: Multi-provider - **Docker**: Simplified deployment - **Traefik**: HTTPS reverse proxy --- ## πŸ“Š Database ```sql CREATE TABLE signatures ( id BIGSERIAL PRIMARY KEY, doc_id TEXT NOT NULL, -- Document ID user_sub TEXT NOT NULL, -- OAuth user ID user_email TEXT NOT NULL, -- User email signed_at TIMESTAMPTZ NOT NULL, -- Signature timestamp payload_hash TEXT NOT NULL, -- Cryptographic hash signature TEXT NOT NULL, -- Ed25519 signature nonce TEXT NOT NULL, -- Anti-replay created_at TIMESTAMPTZ DEFAULT now(), -- Immutable referer TEXT, -- Source (optional) prev_hash TEXT, UNIQUE (doc_id, user_sub) -- One signature per user/doc ); ``` **Guarantees**: - βœ… **Uniqueness**: One user = one signature per document - βœ… **Immutability**: `created_at` protected by trigger - βœ… **Integrity**: SHA-256 hash to detect modifications - βœ… **Non-repudiation**: Ed25519 signature cryptographically provable --- ## πŸš€ Production Deployment ### docker-compose.yml ```yaml version: '3.8' services: ackapp: image: btouchard/ackify-ce:latest environment: ACKIFY_BASE_URL: https://ackify.company.com ACKIFY_DB_DSN: postgres://user:pass@postgres:5432/ackdb?sslmode=require ACKIFY_OAUTH_CLIENT_ID: ${ACKIFY_OAUTH_CLIENT_ID} ACKIFY_OAUTH_CLIENT_SECRET: ${ACKIFY_OAUTH_CLIENT_SECRET} ACKIFY_OAUTH_COOKIE_SECRET: ${ACKIFY_OAUTH_COOKIE_SECRET} labels: - "traefik.enable=true" - "traefik.http.routers.ackify.rule=Host(`ackify.company.com`)" - "traefik.http.routers.ackify.tls.certresolver=letsencrypt" postgres: image: postgres:15-alpine environment: POSTGRES_DB: ackdb POSTGRES_USER: ackuser POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data ``` ### Production variables ```bash # Enhanced security ACKIFY_OAUTH_COOKIE_SECRET="$(openssl rand -base64 64)" # AES-256 ACKIFY_ED25519_PRIVATE_KEY="$(openssl genpkey -algorithm Ed25519 | base64 -w 0)" # HTTPS mandatory ACKIFY_BASE_URL="https://ackify.company.com" # Secure PostgreSQL ACKIFY_DB_DSN="postgres://user:pass@postgres:5432/ackdb?sslmode=require" ``` --- ## πŸ“‹ Complete API ### Authentication - `GET /login?next=` - OAuth2 login - `GET /logout` - Logout - `GET /oauth2/callback` - OAuth2 callback ### Signatures - `GET /sign?doc=` - Signature interface - `POST /sign` - Create signature - `GET /signatures` - My signatures (auth required) ### Consultation - `GET /status?doc=` - JSON all signatures - `GET /status.png?doc=&user=` - PNG badge ### Integration - `GET /oembed?url=` - oEmbed metadata - `GET /embed?doc=` - HTML widget ### Monitoring - `GET /health` - Health check (alias: `/healthz`) ### Admin - `GET /admin` - Dashboard (restricted) - `GET /admin/docs/{docID}` - Signatures for a document - `GET /admin/api/chain-integrity/{docID}` - Chain integrity JSON Access control: set `ACKIFY_ADMIN_EMAILS` with a comma-separated list of admin emails (exact match, case-insensitive). Example: ```bash ACKIFY_ADMIN_EMAILS="alice@company.com,bob@company.com" ``` --- ## πŸ” Development & Testing ### Local build ```bash # Dependencies go mod tidy # Build go build ./cmd/community # Linting go fmt ./... go vet ./... # Tests (TODO: add tests) go test -v ./... ``` ### Docker development ```bash # Build image docker build -t ackify-ce:dev . # Run with local database docker run -p 8080:8080 --env-file .env ackify-ce:dev # Optional: static analysis go install honnef.co/go/tools/cmd/staticcheck@latest staticcheck ./... ``` --- ## 🀝 Support ### Help & Documentation - πŸ› **Issues**: [GitHub Issues](https://github.com/btouchard/ackify-ce/issues) - πŸ’¬ **Discussions**: [GitHub Discussions](https://github.com/btouchard/ackify-ce/discussions) ### License (AGPLv3) Distributed under the GNU Affero General Public License v3.0. See [LICENSE](LICENSE) for details. --- **Developed with ❀️ by [Benjamin TOUCHARD](mailto:benjamin@kolapsis.com)**