feat: standardize environment variable names with ACKIFY_ prefix

- Renamed all environment variables to use consistent ACKIFY_ prefix
- Updated configuration files, Docker compose, and build documentation
- Modified database connection variables and OAuth configuration
- Updated crypto key environment variable reference
- Ensured consistency across all configuration files
This commit is contained in:
Benjamin
2025-09-15 20:55:58 +02:00
parent 609cdfce4d
commit aebef77434
11 changed files with 81 additions and 77 deletions

View File

@@ -1,43 +1,43 @@
# Application Configuration
APP_NAME=ackify-ce
APP_DNS=your-domain.com
APP_BASE_URL=https://your-domain.com
APP_ORGANISATION="Your Organization Name"
# Database Configuration
POSTGRES_USER=ackifyr
POSTGRES_PASSWORD=your_secure_password
POSTGRES_DB=ackify
DB_DSN=postgres://user:pass@db:5432/ack?sslmode=disable
# Application Configuration
APP_NAME=ackify
APP_DNS=sign.your-domain.com
ACKIFY_BASE_URL=https://sign.your-domain.com
ACKIFY_ORGANISATION="Your Organization Name"
ACKIFY_DB_DSN="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ackify-db:5432/${POSTGRES_DB}?sslmode=disable"
# OAuth2 Configuration - Generic Provider
OAUTH_CLIENT_ID=your_oauth_client_id
OAUTH_CLIENT_SECRET=your_oauth_client_secret
OAUTH_ALLOWED_DOMAIN=your-organization.com
ACKIFY_OAUTH_CLIENT_ID=your_oauth_client_id
ACKIFY_OAUTH_CLIENT_SECRET=your_oauth_client_secret
ACKIFY_OAUTH_ALLOWED_DOMAIN=your-organization.com
# OAuth2 Provider Configuration
# Use OAUTH_PROVIDER to configure popular providers automatically:
# Use ACKIFY_OAUTH_PROVIDER to configure popular providers automatically:
# - "google" for Google OAuth2
# - "github" for GitHub OAuth2
# - "gitlab" for GitLab OAuth2 (set OAUTH_GITLAB_URL if self-hosted)
# - "github" for GitHub OAuth2
# - "gitlab" for GitLab OAuth2 (set ACKIFY_OAUTH_GITLAB_URL if self-hosted)
# - Leave empty for custom provider (requires manual URL configuration)
OAUTH_PROVIDER=google
ACKIFY_OAUTH_PROVIDER=google
# Custom OAuth2 Provider URLs (only needed if OAUTH_PROVIDER is empty)
# OAUTH_AUTH_URL=https://your-provider.com/oauth/authorize
# OAUTH_TOKEN_URL=https://your-provider.com/oauth/token
# OAUTH_USERINFO_URL=https://your-provider.com/api/user
# OAUTH_SCOPES=openid,email
# Custom OAuth2 Provider URLs (only needed if ACKIFY_OAUTH_PROVIDER is empty)
# ACKIFY_OAUTH_AUTH_URL=https://your-provider.com/oauth/authorize
# ACKIFY_OAUTH_TOKEN_URL=https://your-provider.com/oauth/token
# ACKIFY_OAUTH_USERINFO_URL=https://your-provider.com/api/user
# ACKIFY_OAUTH_SCOPES=openid,email
# GitLab specific (if using gitlab as provider and self-hosted)
# OAUTH_GITLAB_URL=https://gitlab.your-company.com
# ACKIFY_OAUTH_GITLAB_URL=https://gitlab.your-company.com
# Security Configuration
OAUTH_COOKIE_SECRET=your_base64_encoded_secret_key
ED25519_PRIVATE_KEY_B64=your_base64_encoded_ed25519_private_key
ACKIFY_OAUTH_COOKIE_SECRET=your_base64_encoded_secret_key
ACKIFY_ED25519_PRIVATE_KEY=your_base64_encoded_ed25519_private_key
# Server Configuration
LISTEN_ADDR=:8080
ACKIFY_LISTEN_ADDR=:8080
# Template Configuration
# ACKIFY_TEMPLATES_DIR=/custom/path/to/templates

View File

@@ -51,14 +51,18 @@ cp .env.example .env
Required environment variables:
- `APP_BASE_URL`: Public URL of your application
- `OAUTH_CLIENT_ID`: OAuth2 client ID
- `OAUTH_CLIENT_SECRET`: OAuth2 client secret
- `DB_DSN`: PostgreSQL connection string
- `OAUTH_COOKIE_SECRET`: Base64-encoded secret for session cookies
- `ACKIFY_BASE_URL`: Public URL of your application
- `ACKIFY_OAUTH_CLIENT_ID`: OAuth2 client ID
- `ACKIFY_OAUTH_CLIENT_SECRET`: OAuth2 client secret
- `ACKIFY_DB_DSN`: PostgreSQL connection string
- `ACKIFY_OAUTH_COOKIE_SECRET`: Base64-encoded secret for session cookies
Optional template configuration:
Optional configuration:
- `ACKIFY_TEMPLATES_DIR`: Custom path to HTML templates directory (defaults to relative path for development, `/app/templates` in Docker)
- `ACKIFY_LISTEN_ADDR`: Server listen address (default: `:8080`)
- `ACKIFY_ED25519_PRIVATE_KEY`: Base64-encoded Ed25519 private key for signatures
- `ACKIFY_OAUTH_PROVIDER`: OAuth provider (`google`, `github`, `gitlab` or empty for custom)
- `ACKIFY_OAUTH_ALLOWED_DOMAIN`: Domain restriction for OAuth users
### OAuth2 Providers

View File

@@ -16,7 +16,7 @@ import (
)
func main() {
var dbDSN = flag.String("db-dsn", os.Getenv("DB_DSN"), "Database DSN")
var dbDSN = flag.String("db-dsn", os.Getenv("ACKIFY_DB_DSN"), "Database DSN")
var migrationsPath = flag.String("migrations-path", "file://migrations", "Path to migrations directory")
flag.Parse()

View File

@@ -5,12 +5,12 @@ services:
image: btouchard/ackify-ce
container_name: ackify-ce-migrate
environment:
APP_BASE_URL: "${APP_BASE_URL}"
APP_ORGANISATION: "${APP_ORGANISATION}"
OAUTH_PROVIDER: "${OAUTH_PROVIDER}"
OAUTH_CLIENT_ID: "${OAUTH_CLIENT_ID}"
OAUTH_CLIENT_SECRET: "${OAUTH_CLIENT_SECRET}"
DB_DSN: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ackify-db:5432/${POSTGRES_DB}?sslmode=disable"
ACKIFY_BASE_URL: "${ACKIFY_BASE_URL}"
ACKIFY_ORGANISATION: "${ACKIFY_ORGANISATION}"
ACKIFY_OAUTH_PROVIDER: "${ACKIFY_OAUTH_PROVIDER}"
ACKIFY_OAUTH_CLIENT_ID: "${ACKIFY_OAUTH_CLIENT_ID}"
ACKIFY_OAUTH_CLIENT_SECRET: "${ACKIFY_OAUTH_CLIENT_SECRET}"
ACKIFY_DB_DSN: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ackify-db:5432/${POSTGRES_DB}?sslmode=disable"
depends_on:
ackify-db:
condition: service_healthy
@@ -25,16 +25,16 @@ services:
container_name: ackify-ce
restart: unless-stopped
environment:
APP_BASE_URL: "https://${APP_DNS}"
APP_ORGANISATION: "${APP_ORGANISATION}"
OAUTH_PROVIDER: "${OAUTH_PROVIDER}"
OAUTH_CLIENT_ID: "${OAUTH_CLIENT_ID}"
OAUTH_CLIENT_SECRET: "${OAUTH_CLIENT_SECRET}"
OAUTH_ALLOWED_DOMAIN: "${OAUTH_ALLOWED_DOMAIN}"
OAUTH_COOKIE_SECRET: "${OAUTH_COOKIE_SECRET}"
DB_DSN: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ackify-db:5432/${POSTGRES_DB}?sslmode=disable"
ED25519_PRIVATE_KEY_B64: "${ED25519_PRIVATE_KEY_B64}"
LISTEN_ADDR: ":8080"
ACKIFY_BASE_URL: "https://${APP_DNS}"
ACKIFY_ORGANISATION: "${ACKIFY_ORGANISATION}"
ACKIFY_OAUTH_PROVIDER: "${ACKIFY_OAUTH_PROVIDER}"
ACKIFY_OAUTH_CLIENT_ID: "${ACKIFY_OAUTH_CLIENT_ID}"
ACKIFY_OAUTH_CLIENT_SECRET: "${ACKIFY_OAUTH_CLIENT_SECRET}"
ACKIFY_OAUTH_ALLOWED_DOMAIN: "${ACKIFY_OAUTH_ALLOWED_DOMAIN}"
ACKIFY_OAUTH_COOKIE_SECRET: "${ACKIFY_OAUTH_COOKIE_SECRET}"
ACKIFY_DB_DSN: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ackify-db:5432/${POSTGRES_DB}?sslmode=disable"
ACKIFY_ED25519_PRIVATE_KEY: "${ACKIFY_ED25519_PRIVATE_KEY}"
ACKIFY_LISTEN_ADDR: ":8080"
depends_on:
ackify-migrate:
condition: service_completed_successfully

View File

@@ -51,21 +51,21 @@ func Load() (*Config, error) {
config := &Config{}
// App config
baseURL := mustGetEnv("APP_BASE_URL")
baseURL := mustGetEnv("ACKIFY_BASE_URL")
config.App.BaseURL = baseURL
config.App.Organisation = mustGetEnv("APP_ORGANISATION")
config.App.Organisation = mustGetEnv("ACKIFY_ORGANISATION")
config.App.SecureCookies = strings.HasPrefix(strings.ToLower(baseURL), "https://")
// Database config
config.Database.DSN = mustGetEnv("DB_DSN")
config.Database.DSN = mustGetEnv("ACKIFY_DB_DSN")
// OAuth config
config.OAuth.ClientID = mustGetEnv("OAUTH_CLIENT_ID")
config.OAuth.ClientSecret = mustGetEnv("OAUTH_CLIENT_SECRET")
config.OAuth.AllowedDomain = os.Getenv("OAUTH_ALLOWED_DOMAIN")
config.OAuth.ClientID = mustGetEnv("ACKIFY_OAUTH_CLIENT_ID")
config.OAuth.ClientSecret = mustGetEnv("ACKIFY_OAUTH_CLIENT_SECRET")
config.OAuth.AllowedDomain = os.Getenv("ACKIFY_OAUTH_ALLOWED_DOMAIN")
// Configure OAuth endpoints based on provider or use custom URLs
provider := strings.ToLower(getEnv("OAUTH_PROVIDER", ""))
provider := strings.ToLower(getEnv("ACKIFY_OAUTH_PROVIDER", ""))
switch provider {
case "google":
config.OAuth.AuthURL = "https://accounts.google.com/o/oauth2/auth"
@@ -78,17 +78,17 @@ func Load() (*Config, error) {
config.OAuth.UserInfoURL = "https://api.github.com/user"
config.OAuth.Scopes = []string{"user:email", "read:user"}
case "gitlab":
gitlabURL := getEnv("OAUTH_GITLAB_URL", "https://gitlab.com")
gitlabURL := getEnv("ACKIFY_OAUTH_GITLAB_URL", "https://gitlab.com")
config.OAuth.AuthURL = fmt.Sprintf("%s/oauth/authorize", gitlabURL)
config.OAuth.TokenURL = fmt.Sprintf("%s/oauth/token", gitlabURL)
config.OAuth.UserInfoURL = fmt.Sprintf("%s/api/v4/user", gitlabURL)
config.OAuth.Scopes = []string{"read_user", "profile"}
default:
// Custom OAuth provider - all URLs must be explicitly set
config.OAuth.AuthURL = mustGetEnv("OAUTH_AUTH_URL")
config.OAuth.TokenURL = mustGetEnv("OAUTH_TOKEN_URL")
config.OAuth.UserInfoURL = mustGetEnv("OAUTH_USERINFO_URL")
scopesStr := getEnv("OAUTH_SCOPES", "openid,email,profile")
config.OAuth.AuthURL = mustGetEnv("ACKIFY_OAUTH_AUTH_URL")
config.OAuth.TokenURL = mustGetEnv("ACKIFY_OAUTH_TOKEN_URL")
config.OAuth.UserInfoURL = mustGetEnv("ACKIFY_OAUTH_USERINFO_URL")
scopesStr := getEnv("ACKIFY_OAUTH_SCOPES", "openid,email,profile")
config.OAuth.Scopes = strings.Split(scopesStr, ",")
}
@@ -99,7 +99,7 @@ func Load() (*Config, error) {
config.OAuth.CookieSecret = cookieSecret
// Server config
config.Server.ListenAddr = getEnv("LISTEN_ADDR", ":8080")
config.Server.ListenAddr = getEnv("ACKIFY_LISTEN_ADDR", ":8080")
return config, nil
}
@@ -124,11 +124,11 @@ func getEnv(key, defaultValue string) string {
// parseCookieSecret parses the cookie secret from environment
func parseCookieSecret() ([]byte, error) {
raw := os.Getenv("OAUTH_COOKIE_SECRET")
raw := os.Getenv("ACKIFY_OAUTH_COOKIE_SECRET")
if raw == "" {
// Generate random 32 bytes for development
secret := securecookie.GenerateRandomKey(32)
fmt.Println("[WARN] OAUTH_COOKIE_SECRET not set, generated volatile secret (sessions reset on restart)")
fmt.Println("[WARN] ACKIFY_OAUTH_COOKIE_SECRET not set, generated volatile secret (sessions reset on restart)")
return secret, nil
}

View File

@@ -30,7 +30,7 @@ func SetupTestDB(t *testing.T) *TestDB {
t.Skip("Skipping integrations test (INTEGRATION_TESTS not set)")
}
dsn := os.Getenv("DB_DSN")
dsn := os.Getenv("ACKIFY_DB_DSN")
if dsn == "" {
dsn = "postgres://postgres:testpassword@localhost:5432/ackify_test?sslmode=disable"
}

View File

@@ -60,7 +60,7 @@ func canonicalPayload(docID string, user *models.User, timestamp time.Time, nonc
// loadOrGenerateKeys loads existing keys or generates new ones
func loadOrGenerateKeys() (ed25519.PrivateKey, ed25519.PublicKey, error) {
b64Key := strings.TrimSpace(os.Getenv("ED25519_PRIVATE_KEY_B64"))
b64Key := strings.TrimSpace(os.Getenv("ACKIFY_ED25519_PRIVATE_KEY"))
if b64Key != "" {
keyBytes, err := base64.StdEncoding.DecodeString(b64Key)

View File

@@ -17,7 +17,7 @@ import (
func TestEd25519Signer_NewEd25519Signer(t *testing.T) {
t.Run("creates new signer successfully", func(t *testing.T) {
// Clear environment variable to force generation
originalKey := os.Getenv("ED25519_PRIVATE_KEY_B64")
originalKey := os.Getenv("ACKIFY_ED25519_PRIVATE_KEY")
os.Unsetenv("ED25519_PRIVATE_KEY_B64")
defer func() {
if originalKey != "" {
@@ -398,7 +398,7 @@ func TestEd25519Signer_GetPublicKey(t *testing.T) {
t.Run("different signers have different public keys", func(t *testing.T) {
// Clear environment to force generation of different keys
originalKey := os.Getenv("ED25519_PRIVATE_KEY_B64")
originalKey := os.Getenv("ACKIFY_ED25519_PRIVATE_KEY")
os.Unsetenv("ED25519_PRIVATE_KEY_B64")
defer func() {
if originalKey != "" {

View File

@@ -19,14 +19,14 @@ import (
"github.com/btouchard/ackify-ce/pkg/crypto"
)
// Server represents the Ackify CE web server
// Server represents the Ackify web server
type Server struct {
httpServer *http.Server
db *sql.DB
router *chi.Mux
}
// NewServer creates a new Ackify CE server instance
// NewServer creates a new Ackify server instance
func NewServer(ctx context.Context) (*Server, error) {
// Initialize infrastructure
cfg, db, tmpl, signer, err := initInfrastructure(ctx)
@@ -212,8 +212,8 @@ func getTemplatesDir() string {
// Fallback for development: check multiple possible paths
possiblePaths := []string{
"templates", // When running from project root
"./templates", // Alternative relative path
"templates", // When running from project root
"./templates", // Alternative relative path
}
for _, path := range possiblePaths {

View File

@@ -10,7 +10,7 @@
</svg>
</div>
<div>
<h2 class="text-2xl font-bold text-white">Ackify CE</h2>
<h2 class="text-2xl font-bold text-white">Ackify</h2>
<p class="text-primary-100">La solution professionnelle pour valider la lecture de vos documents</p>
</div>
</div>

View File

@@ -34,7 +34,7 @@
</div>
<div>
<h3 class="text-xl font-bold text-success-700 mb-2">Document Déjà Signé</h3>
<h3 class="text-xl font-bold text-success-700 mb-2">Document signé</h3>
<p class="text-slate-600 mb-4">Vous avez confirmé la lecture de ce document</p>
<div class="bg-success-50 border border-success-200 rounded-2xl p-6">
@@ -58,8 +58,8 @@
</div>
<div>
<h3 class="text-xl font-bold text-warning-700 mb-2">Document Non Signé</h3>
<p class="text-slate-600 mb-6">Vous devez confirmer avoir lu et approuvé ce document</p>
<h3 class="text-xl font-bold text-warning-700 mb-2">Document à signer</h3>
<p class="text-slate-600 mb-6">Vous devez confirmer avoir lu et compris ce document</p>
<div class="bg-warning-50 border border-warning-200 rounded-2xl p-6 mb-6">
<div class="flex items-start space-x-3">
@@ -82,7 +82,7 @@
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
</svg>
<span>J'ai lu et j'approuve ce document</span>
<span>Je certifie avoir lu et compris ce document</span>
</button>
</form>
</div>
@@ -95,11 +95,11 @@
<div class="bg-white rounded-2xl border border-slate-200 p-6">
<h4 class="font-semibold text-slate-900 mb-4">Actions supplémentaires</h4>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<a href="/embed?doc={{.DocID}}" target="_blank" class="flex items-center justify-center space-x-2 px-4 py-3 bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-xl transition-colors text-sm font-medium text-center">
<a href="/signatures" target="_blank" class="flex items-center justify-center space-x-2 px-4 py-3 bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-xl transition-colors text-sm font-medium text-center">
<svg class="w-4 h-4 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v14a2 2 0 002 2z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/>
</svg>
<span>Widget embarqué</span>
<span>Voir mes signatures</span>
</a>
<a href="/" class="flex items-center justify-center space-x-2 px-4 py-3 bg-primary-100 hover:bg-primary-200 text-primary-700 rounded-xl transition-colors text-sm font-medium text-center">