Files
boc/backend/handlers/compliance.go
T
Bernt 78b57273e2 security: Add proper authentication, RBAC, and tenant isolation
- Add password hashing with bcrypt
- Add AuthService with proper login
- Add password strength validation
- Add RBAC middleware (AdminOnly, ManagerOrAdmin)
- Add tenant isolation middleware
- Update CRM handler with tenant filtering
- Add JWT fallback for development mode
- Add user context helpers
- Build successful
2026-08-10 12:52:48 +00:00

286 lines
8.5 KiB
Go

package handlers
import (
"database/sql"
"net/http"
"time"
)
// ComplianceHandler hanterar ISO, GDPR, risk och full legal compliance
type ComplianceHandler struct {
DB *sql.DB
}
func NewComplianceHandler(db *sql.DB) *ComplianceHandler {
return &ComplianceHandler{DB: db}
}
// ISOCertification representerar en ISO-certifiering
type ISOCertification struct {
ID string `json:"id"`
Standard string `json:"standard"`
Name string `json:"name"`
Status string `json:"status"`
IssuedAt time.Time `json:"issued_at"`
ExpiresAt time.Time `json:"expires_at"`
Issuer string `json:"issuer"`
Scope string `json:"scope"`
EntityID string `json:"entity_id"`
Auditor string `json:"auditor"`
LastAudit time.Time `json:"last_audit"`
NextAudit time.Time `json:"next_audit"`
Findings int `json:"findings"`
MajorFindings int `json:"major_findings"`
}
// GDPRRecord representerar en GDPR/behandlingsregister-post
type GDPRRecord struct {
ID string `json:"id"`
EntityID string `json:"entity_id"`
Purpose string `json:"purpose"`
DataSubjects []string `json:"data_subjects"`
DataTypes []string `json:"data_types"`
LegalBasis string `json:"legal_basis"`
Retention string `json:"retention"`
Processors []string `json:"processors"`
DPAExists bool `json:"dpa_exists"`
CrossBorder bool `json:"cross_border"`
ImpactAssessment bool `json:"impact_assessment"`
LastReview string `json:"last_review"`
}
// RiskEntry representerar en risk
type RiskEntry struct {
ID string `json:"id"`
EntityID string `json:"entity_id"`
Category string `json:"category"`
Description string `json:"description"`
Probability int `json:"probability"`
Impact int `json:"impact"`
Score int `json:"score"`
Mitigation string `json:"mitigation"`
Owner string `json:"owner"`
Status string `json:"status"`
ReviewDate time.Time `json:"review_date"`
}
// LegalCase representerar ett juridiskt ärende
type LegalCase struct {
ID string `json:"id"`
EntityID string `json:"entity_id"`
Title string `json:"title"`
Type string `json:"type"`
Status string `json:"status"`
Priority string `json:"priority"`
Description string `json:"description"`
OpposingParty string `json:"opposing_party"`
Lawyer string `json:"lawyer"`
OpenedAt time.Time `json:"opened_at"`
ClosedAt *time.Time `json:"closed_at,omitempty"`
Value float64 `json:"value"`
Currency string `json:"currency"`
}
// Policy representerar en policy
type Policy struct {
ID string `json:"id"`
Title string `json:"title"`
Category string `json:"category"`
Version string `json:"version"`
Status string `json:"status"`
ApprovedBy string `json:"approved_by"`
ApprovedAt time.Time `json:"approved_at"`
ReviewDate time.Time `json:"review_date"`
EntityID string `json:"entity_id"`
URL string `json:"url"`
}
// GetISO returnerar alla ISO-certifieringar
func (h *ComplianceHandler) GetISO(w http.ResponseWriter, r *http.Request) {
certs := []ISOCertification{
{
ID: "iso-27001-001",
Standard: "ISO/IEC 27001:2022",
Name: "Information Security Management",
Status: "active",
IssuedAt: time.Now().Add(-180 * 24 * time.Hour),
ExpiresAt: time.Now().Add(185 * 24 * time.Hour),
Issuer: "Bureau Veritas",
Scope: "All AMOS cloud infrastructure and data processing",
EntityID: "lvx-ab",
Auditor: "Anna Lindgren",
LastAudit: time.Now().Add(-30 * 24 * time.Hour),
NextAudit: time.Now().Add(60 * 24 * time.Hour),
Findings: 2,
MajorFindings: 0,
},
{
ID: "iso-9001-001",
Standard: "ISO 9001:2015",
Name: "Quality Management",
Status: "active",
IssuedAt: time.Now().Add(-365 * 24 * time.Hour),
ExpiresAt: time.Now().Add(365 * 24 * time.Hour),
Issuer: "SGS",
Scope: "AI model development and deployment processes",
EntityID: "lvx-ab",
Auditor: "Marcus Berg",
LastAudit: time.Now().Add(-60 * 24 * time.Hour),
NextAudit: time.Now().Add(120 * 24 * time.Hour),
Findings: 0,
MajorFindings: 0,
},
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"certifications": certs,
"summary": map[string]interface{}{
"total": len(certs),
"active": 2,
"in_progress": 1,
"planned": 1,
"expiring_soon": 0,
},
})
}
// GetGDPR returnerar GDPR-register
func (h *ComplianceHandler) GetGDPR(w http.ResponseWriter, r *http.Request) {
records := []GDPRRecord{
{
ID: "gdpr-001",
EntityID: "lvx-ab",
Purpose: "quiXzoom användarregistrering och verifiering",
DataSubjects: []string{"Zoomers", "Kunder"},
DataTypes: []string{"namn", "email", "telefon", "ID-dokument", "selfie"},
LegalBasis: "contract",
Retention: "3 år efter avslutat avtal",
Processors: []string{"AWS eu-north-1", "Stripe"},
DPAExists: true,
CrossBorder: false,
ImpactAssessment: true,
LastReview: "2026-05-15",
},
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"records": records,
})
}
// GetRisks returnerar riskregister
func (h *ComplianceHandler) GetRisks(w http.ResponseWriter, r *http.Request) {
risks := []RiskEntry{
{
ID: "risk-001",
EntityID: "lvx-ab",
Category: "financial",
Description: "Kundkoncentration — 60% av intäkter från 3 kunder",
Probability: 3,
Impact: 4,
Score: 12,
Mitigation: "Expandera kundbas, mål: max 30% per kund",
Owner: "CFO",
Status: "active",
ReviewDate: time.Now().Add(30 * 24 * time.Hour),
},
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"risks": risks,
"summary": map[string]interface{}{
"total": len(risks),
"high_risk": 1,
"medium_risk": 2,
"low_risk": 1,
"mitigated": 1,
"exposure_sek": 500000,
},
})
}
// GetLegalCases returnerar juridiska ärenden från databasen
func (h *ComplianceHandler) GetLegalCases(w http.ResponseWriter, r *http.Request) {
rows, err := h.DB.Query(`
SELECT case_id, entity_id, title, case_type, status, priority, description, opposing_party, lawyer, opened_at, value, currency
FROM boc_legal_cases
ORDER BY opened_at DESC
`)
if err != nil {
writeError(w, http.StatusInternalServerError, "database error")
return
}
defer rows.Close()
var cases []LegalCase
for rows.Next() {
var c LegalCase
var lawyer sql.NullString
if err := rows.Scan(&c.ID, &c.EntityID, &c.Title, &c.Type, &c.Status, &c.Priority, &c.Description, &c.OpposingParty, &lawyer, &c.OpenedAt, &c.Value, &c.Currency); err != nil {
continue
}
if lawyer.Valid {
c.Lawyer = lawyer.String
}
cases = append(cases, c)
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"cases": cases,
"summary": map[string]interface{}{
"total": len(cases),
"active": countCasesByStatus(cases, "active"),
"pending": countCasesByStatus(cases, "pending"),
"closed": countCasesByStatus(cases, "closed"),
"exposure": calculateExposure(cases),
},
})
}
// GetPolicies returnerar policies
func (h *ComplianceHandler) GetPolicies(w http.ResponseWriter, r *http.Request) {
policies := []Policy{
{
ID: "pol-001",
Title: "Information Security Policy",
Category: "security",
Version: "2.1",
Status: "active",
ApprovedBy: "Erik Svensson",
ApprovedAt: time.Now().Add(-90 * 24 * time.Hour),
ReviewDate: time.Now().Add(275 * 24 * time.Hour),
EntityID: "lvx-ab",
URL: "/policies/infosec-v2.1.pdf",
},
}
writeJSON(w, http.StatusOK, map[string]interface{}{
"ok": true,
"policies": policies,
})
}
func countCasesByStatus(cases []LegalCase, status string) int {
count := 0
for _, c := range cases {
if c.Status == status {
count++
}
}
return count
}
func calculateExposure(cases []LegalCase) float64 {
var total float64
for _, c := range cases {
if c.Status == "active" || c.Status == "pending" {
total += c.Value
}
}
return total
}