Commit Graph

35 Commits

Author SHA1 Message Date
Benjamin
8ef5bb38cb fix: accept 'ref' as fallback for 'doc' query parameter
Keep backward compatibility for external integrations that still use
the old ?ref= parameter while recommending ?doc= to avoid privacy
extensions blocking.
2026-02-05 23:35:09 +01:00
Benjamin
2449e7ccee feat: add owner-based expected signers management
Allow non-admin document owners to add and remove expected signers for their documents via new endpoints:
- POST /users/me/documents/{docId}/signers
- DELETE /users/me/documents/{docId}/signers/{email}

Closes #17

fix: escape database names in SQL and add owner-based document management

- Quote PostgreSQL identifiers with double-quotes in migrations to support database names containing special characters like hyphens (fixes #16)
- Add CanManageDocument to Authorizer interface for ownership checks
- Add owner-based document management
- Non-admin users can now manage documents they created when ACKIFY_ONLY_ADMIN_CAN_CREATE=false (fixes #17)
- Return 403 for owner routes when ACKIFY_ONLY_ADMIN_CAN_CREATE=true

Closes #16

refactor: move TenantProvider interface to pkg/providers
- Centralize all provider interfaces in pkg/providers package for consistency with Authorizer and other capability provider interfaces.
2026-02-05 20:57:30 +01:00
Benjamin
bff75aafbe fix: persist options when uploading documents & dynamic config OnlyAdminCanCreate
Reader options (readMode, allowDownload, requireFullRead, verifyChecksum)
were not being saved during document upload.

SimpleAuthorizer now reads the setting dynamically from ConfigService
instead of using a static value set at startup. This allows admins to
toggle document creation permissions via the settings UI without
requiring a server restart.

Fixes #14
Fixes #15
2026-01-22 15:14:13 +01:00
Benjamin
71e5d66550 fix: update SHM sdk 2026-01-21 00:21:44 +01:00
Benjamin
6ce67b02d4 fix: add SHM directory to store identity file (must be persisted on host) 2026-01-20 22:42:40 +01:00
Benjamin
8a0d79ac65 fix: user document allocation
refacto: vue components extract, sign & reminder list, align tests to new components
2026-01-20 09:54:36 +01:00
Benjamin
998d227898 refacto(backend): cleaning dead code 2026-01-17 01:49:41 +01:00
Benjamin
493d915fa7 refactor(server): encapsulate service initialization in ServerBuilder
Move all service creation (I18n, Email, MagicLink, Session, Config)
from main.go into ServerBuilder.Build(), making main.go minimal and
self-contained.

- ServerBuilder now only requires WithDB() and WithTenantProvider()
- AuthProvider and Authorizer have sensible CE defaults
- Rename DynamicAuthProvider → auth.Provider for simplicity
- Remove unused With* methods for internal services
2026-01-16 14:43:58 +01:00
Benjamin
b0ef28b0ae refactor(config): replace window variables with /api/v1/config endpoint
- Add new config handler to serve public app configuration
- Create Pinia config store to load and cache configuration
- Remove window variable injection from static.go and index.html
- Update all components to use config store instead of window vars
- Remove deprecated /api/v1/auth/config endpoint (merged into /config)
- Update Cypress tests with proper type annotations
2026-01-16 01:04:53 +01:00
Benjamin
421ffb3288 refacto: mv internal/domain/models/ → pkg/models/ 2026-01-15 16:16:56 +01:00
Benjamin
fb33fd424d refactor: consolidate dependency injection and improve auth architecture
- Move service initialization (MagicLink, Email, i18n) to main.go
- Change signature lookup from user_sub to email for cross-auth consistency
- Remove OauthService wrapper, simplify auth layer
- Pass parent context to workers for graceful shutdown
- Fix IP extraction from RemoteAddr with port
- Add compact mode to SignatureList component
- Update Cypress tests with new data-testid attributes
2026-01-14 12:34:11 +01:00
Benjamin
2d78294f55 refactor(auth): unify AuthProvider interface with dynamic config support
- Create unified AuthProvider interface in pkg/providers/interfaces.go
  supporting OIDC, MagicLink, and session management
- Implement DynamicAuthProvider that reads config from ConfigService
  on each request, enabling hot-reload of auth settings
- Simplify ServerBuilder by removing separate oauthProvider and flags
- Consolidate auth handlers into single handler.go using unified interface
- Remove obsolete providers (oauth_provider.go, magiclink_provider.go)
- Remove separate magic_link_handler.go and reminder_auth_handler.go
- Update tests with new mockAuthProvider implementing full interface
- Fix config_service_test.go SMTP validation (requires Host + From)
2026-01-13 08:59:20 +01:00
Benjamin
9b28f78ce9 feat(admin): add tenant configuration UI with hot-reload support
Add admin settings page allowing runtime configuration of:
- SMTP settings with connection testing
- OIDC/OAuth2 authentication with validation
- S3 storage configuration with connectivity check

Backend includes config service with atomic hot-reload,
encrypted secrets storage, and environment seeding on startup.
2026-01-12 22:46:04 +01:00
Benjamin
fb9dab2f0f feat: add document storage and integrated PDF viewer
Storage:
- Add S3 and local storage providers for document uploads
- Support file upload with checksum calculation
- Fix S3 upload for non-TLS connections (MinIO)

Document viewer:
- Add PDF.js-based viewer with scroll tracking
- Implement checksum verification on document load
- Add reader options (read mode, download, require full read)
- Auto-detect read completion for signed documents

API:
- Add document upload endpoint with storage integration
- Add proxy endpoint for stored documents
- Extend document metadata with storage and reader fields
2026-01-08 20:39:34 +01:00
Benjamin
c2c096dd3c wip 2025-12-27 22:16:54 +01:00
Benjamin
bc53b3ece9 feat: add anonymous telemetry for usage metrics
- Integrate SHM SDK (v1.2.0) to collect anonymous usage statistics
- Track documents, confirmations, webhooks and reminders count
- Add ACKIFY_TELEMETRY env var (disabled by default, opt-in)
2025-12-22 19:04:32 +01:00
Benjamin
44431dabf4 feat(rls): move ackify_app role creation from init script to migrate tool
BREAKING CHANGE: ACKIFY_APP_PASSWORD environment variable is now required for RLS support. The migrate tool creates the ackify_app role before running migrations, ensuring compatibility with existing deployments.

Changes:
- Add ensureAppRole() in cmd/migrate to create/update ackify_app role
- Remove docker/init-scripts/01-create-app-user.sh (no longer needed)
- Update compose.yml: add ACKIFY_APP_PASSWORD, backend connects as ackify_app
- Update migration 0016: remove conditional role creation
- Add RLS documentation (docs/en/configuration/rls.md, docs/fr/configuration/rls.md)
- Update configuration docs with RLS section and security checklist

Migration path for existing deployments:
1. Set ACKIFY_APP_PASSWORD in .env
2. Run docker compose up (migrate will create the role automatically)
2025-12-15 23:59:06 +01:00
Benjamin
ab6cdbb383 refactor(go): rename module to github.com/btouchard/ackify-ce/backend
Enable importing backend packages in SaaS project by aligning module
path with its location in the repository.
2025-12-08 19:01:28 +01:00
Benjamin
24e2de2922 refactor(arch): enforce strict layered architecture with private interfaces
Apply Clean Architecture principles throughout the codebase to eliminate tight coupling between layers. Handlers now depend exclusively on services through private interfaces, never directly on repositories.
Introduce a ServerBuilder pattern with pluggable capability providers.

refactor(auth): introduce injectable AuthorizerService

Replace hardcoded AdminEmails and OnlyAdminCanCreate config fields
with an injectable AuthorizerService. This improves testability and
follows the dependency injection pattern used elsewhere in the codebase.

- Create AuthorizerService in application/services/
- Define minimal Authorizer interfaces in consuming packages
- Update middleware, handlers, and router to use injected authorizer
- Update all affected tests with mock implementations

refactor(build): move go.mod to backend directory
Move Go module files from project root to backend/ directory while keeping the module name as github.com/btouchard/ackify-ce.
This improves project structure by keeping Go-specific files within the Go codebase directory.

# Conflicts:
#	backend/internal/application/services/checksum_service_test.go
#	backend/internal/application/services/document_service.go
#	backend/internal/application/services/document_service_duplicate_test.go
#	backend/internal/application/services/document_service_test.go
#	backend/internal/presentation/api/documents/handler.go
#	backend/internal/presentation/api/documents/handler_test.go
#	backend/internal/presentation/api/router.go
#	backend/pkg/web/server.go
2025-12-08 16:07:03 +01:00
Benjamin
1b108ed874 refacto(backend): extract coreapp packages for DI and authorization
- Add pkg/coreapp/ with service interfaces and dependency injection
- Add DocumentAuthorizer for document access control
- Add ExpectedSignerService for expected signers management
- Simplify router and handlers by using coreapp dependencies
2025-12-04 15:19:01 +01:00
Benjamin
796d327442 feat(tenant): add tenant support
- Add instance_metadata table with unique UUID per instance
- Add tenant_id column to all business tables (documents, signatures, expected_signers, webhooks, reminder_logs, email_queue, checksum_verifications, webhook_deliveries)
- Backfill existing data with instance tenant UUID
- Create TenantProvider interface and SingleTenantProvider implementation
- Update all repositories to filter by tenant_id
- Add immutability triggers to prevent tenant_id modification after creation

Migration 0015 includes:
- Schema changes with indexes for tenant_id columns
- SQL backfill for existing data
- Trigger functions for data integrity
2025-12-03 23:46:09 +01:00
Benjamin
249849b3ed feat(tenant): add tenant support
- Add instance_metadata table with unique UUID per instance
- Add tenant_id column to all business tables (documents, signatures, expected_signers, webhooks, reminder_logs, email_queue, checksum_verifications, webhook_deliveries)
- Backfill existing data with instance tenant UUID
- Create TenantProvider interface and SingleTenantProvider implementation
- Update all repositories to filter by tenant_id
- Add immutability triggers to prevent tenant_id modification after creation

Migration 0015 includes:
- Schema changes with indexes for tenant_id columns
- SQL backfill for existing data
- Trigger functions for data integrity
2025-12-03 22:24:12 +01:00
Benjamin
686edc6123 feat(mail): fix mail suject alway in english, now is based on i18n 2025-12-03 12:21:44 +01:00
Benjamin
533e62fcfe feat(csv): import expected signature from CSV 2025-11-26 23:37:21 +01:00
Benjamin
5cd91654e0 feat: configurable rate limiting and comprehensive E2E test suite
Rate Limiting Configuration:
- Add ACKIFY_AUTH_MAGICLINK_RATE_LIMIT_EMAIL (default: 3/hour)
- Add ACKIFY_AUTH_MAGICLINK_RATE_LIMIT_IP (default: 10/hour)
- Add ACKIFY_AUTH_RATE_LIMIT (default: 5/min)
- Add ACKIFY_DOCUMENT_RATE_LIMIT (default: 10/min)
- Add ACKIFY_GENERAL_RATE_LIMIT (default: 100/min)

E2E Test Suite:
- 01-signature-workflow: Complete signature flow validation
- 02-signature-uniqueness: Constraint enforcement and duplicate prevention
- 03-admin-signers-management: Expected signers CRUD operations
- 04-admin-email-reminders: SMTP reminder functionality
- 05-document-creation-by-url: URL-based document initialization
- 06-my-signatures-page: User signature list and navigation
- 07-admin-document-deletion: Cascade deletion verification
- 08-admin-route-protection: Access control validation
- 09-complete-workflow: End-to-end multi-user scenario
- 10-unexpected-signatures: Handling of non-expected signers
2025-11-23 22:27:55 +01:00
Benjamin
f6c75b3497 refactor(security): use structured logger to prevent sensitive data exposure
Changes:
- Replace fmt.Println with logger.Logger.Warn in config loading
- Remove client_id and auth URLs from OAuth provider logs
- Remove user email, name, and sub from authentication logs
- Use structured logging for worker shutdown errors
- Fix MagicLink status logging (only log when actually enabled)
2025-11-23 00:36:49 +01:00
Benjamin
da1f300d2d feat(admin): improve email reminders UX and fix signer deletion
Backend changes:
- Add SMTPEnabled flag to distinguish SMTP service from MagicLink authentication
- Fix URL-encoded email decoding in DELETE /signers/{email} endpoint
- Add detailed error logging for expected signer removal operations
- Initialize ReminderAsync and MagicLink services unconditionally
- Update config tests to reflect new MagicLink requires explicit enabling

Frontend changes:
- Add ACKIFY_SMTP_ENABLED window variable for feature detection
- Hide delete button for expected signers who have already signed
- Show email reminders card only when SMTP enabled or history exists
- Display informative alert when SMTP disabled but reminder history present
- Add i18n translations for email service disabled message (5 languages)

These changes improve admin experience by preventing invalid operations
(deleting signers who signed, sending emails without SMTP) and providing
clear feedback about feature availability.
2025-11-22 00:43:35 +01:00
Benjamin
aa5fee90f6 feat(admin): add option to restrict document creation to admins only
Add new configuration option ACKIFY_ONLY_ADMIN_CAN_CREATE (default: false) to control who can create documents.

Backend changes:
- Add OnlyAdminCanCreate config field to AppConfig
- Implement authorization checks in document handlers
- Protect POST /documents and GET /documents/find-or-create endpoints
- Add unit tests for admin-only document creation (4 tests)

Frontend changes:
- Inject ACKIFY_ONLY_ADMIN_CAN_CREATE to window object
- Hide DocumentForm component for non-admin users when enabled
- Add i18n translations (en, fr, es, de, it)
- Display warning message for non-admin users

Documentation:
- Update .env.example files with new variable
- Update configuration docs (en/fr)
- Update install script to prompt for restriction option
- Update install/README.md

When enabled, only users listed in ACKIFY_ADMIN_EMAILS can create new documents. Both direct creation and find-or-create endpoints are protected.
2025-11-06 16:08:03 +01:00
Benjamin
a27f051838 feat(auth): implement reminder authentication tokens
Add authentication tokens embedded in reminder emails allowing users to
authenticate and sign documents in one click.

Changes:
- Add 'purpose' (login/reminder_auth) and 'doc_id' columns to magic_link_tokens
- Implement CreateReminderAuthToken (24h validity) and VerifyReminderAuthToken
- Create reminder auth handler and route (/api/v1/auth/reminder-link/verify)
- Update ReminderService and ReminderAsyncService to generate auth tokens
- Fix table name mismatch: magic_links → magic_link_tokens throughout
- Reorder service initialization in server.go for proper dependencies

Token validity:
- Magic Link: 15 minutes (login)
- Reminder Auth: 24 hours (document signature)

The reminder auth flow:
1. Admin sends reminder
2. User receives email with auth link
3. User clicks link → auto-authenticated if not logged in
4. User redirected to document signature page
5. If already authenticated with correct account, skip auth step
2025-11-06 13:43:49 +01:00
Benjamin
32b469f04e feat: add magic link authentication
- Now can activate OIDC and/or MagicLink for user authentication.
- Add page to choose authentication method (if only OIDC is enabled, auto redirecting to login screen)
2025-11-05 15:01:23 +01:00
Benjamin
289f8cd53b fix(embed): add middleware to authorize embed create document (with hard rate limit) 2025-10-27 23:24:07 +01:00
Benjamin
44c8cbef04 feat(vers): add version number to front 2025-10-27 18:34:27 +01:00
Benjamin
925d363ac3 feat(webhook): ajout de la prise en charge des webhooks signés
- Envoi des événements vers des URLs configurées
- Signature HMAC-SHA256 via en-tête X-Signature (secret partagé)
- Retentatives avec backoff exponentiel et jitter
- Timeout réseau et gestion des erreurs/transitoires
- Idempotence par event_id et journalisation structurée
- Paramètres: WEBHOOK_URLS, WEBHOOK_SECRET, WEBHOOK_TIMEOUT_MS, WEBHOOK_MAX_RETRIES
2025-10-27 15:11:06 +01:00
Benjamin
68426bc882 feat: add PKCE support to OAuth2 flow for enhanced security
- Implement PKCE (Proof Key for Code Exchange) with S256 method
- Add crypto/pkce module with code verifier and challenge generation
- Modify OAuth flow to include code_challenge in authorization requests
- Update HandleCallback to validate code_verifier during token exchange
- Extend session lifetime from 7 to 30 days
- Add comprehensive unit tests for PKCE functions
- Maintain backward compatibility with fallback for non-PKCE sessions
- Add detailed logging for OAuth flow with PKCE tracking

PKCE enhances security by preventing authorization code interception
attacks, as recommended by OAuth 2.1 and OIDC standards.

feat: add encrypted refresh token storage with automatic cleanup

- Add oauth_sessions table for storing encrypted refresh tokens
- Implement AES-256-GCM encryption for refresh tokens using cookie secret
- Create OAuth session repository with full CRUD operations
- Add SessionWorker for automatic cleanup of expired sessions
- Configure cleanup to run every 24h for sessions older than 37 days
- Modify OAuth flow to store refresh tokens after successful authentication
- Track client IP and user agent for session security validation
- Link OAuth sessions to user sessions via session ID
- Add comprehensive encryption tests with security validations
- Integrate SessionWorker into server lifecycle with graceful shutdown

This enables persistent OAuth sessions with secure token storage,
reducing the need for frequent re-authentication from 7 to 30 days.
2025-10-26 02:32:10 +02:00
Benjamin
e95185f9c7 feat: migrate to Vue.js SPA with API-first architecture
Major refactoring to modernize the application architecture:

Backend changes:
- Restructure API with v1 versioning and modular handlers
- Add comprehensive OpenAPI specification
- Implement RESTful endpoints for documents, signatures, admin
- Add checksum verification system for document integrity
- Add server-side runtime injection of ACKIFY_BASE_URL and meta tags
- Generate dynamic Open Graph/Twitter Card meta tags for unfurling
- Remove legacy HTML template handlers
- Isolate backend source on dedicated folder
- Improve tests suite

Frontend changes:
- Migrate from Go templates to Vue.js 3 SPA with TypeScript
- Add Tailwind CSS with shadcn/vue components
- Implement i18n support (fr, en, es, de, it)
- Add admin dashboard for document and signer management
- Add signature tracking with file checksum verification
- Add embed page with sign button linking to main app
- Implement dark mode and accessibility features
- Auto load file to compute checksum

Infrastructure:
- Update Dockerfile for SPA build process
- Simplify deployment with embedded frontend assets
- Add migration for checksum_verifications table

This enables better UX, proper link previews on social platforms,
and provides a foundation for future enhancements.
2025-10-26 02:32:10 +02:00