| package report |
|
|
| import ( |
| "reflect" |
| "strings" |
|
|
| "github.com/pinchtab/pinchtab/internal/config" |
| ) |
|
|
| func ApplyRecommendedSecurityDefaults(fc *config.FileConfig) { |
| defaults := config.DefaultFileConfig() |
| if fc == nil { |
| return |
| } |
| fc.Server.Bind = defaults.Server.Bind |
| fc.Security = defaults.Security |
| if strings.TrimSpace(fc.Server.Token) == "" { |
| token, err := config.GenerateAuthToken() |
| if err == nil { |
| fc.Server.Token = token |
| } |
| } |
| } |
|
|
| func applyRecommendedSecurityDefaults(fc *config.FileConfig) { |
| ApplyRecommendedSecurityDefaults(fc) |
| } |
|
|
| func RestoreSecurityDefaults() (string, bool, error) { |
| fc, configPath, err := config.LoadFileConfig() |
| if err != nil { |
| return "", false, err |
| } |
| before := securityDefaultsSnapshot(fc) |
| ApplyRecommendedSecurityDefaults(fc) |
| after := securityDefaultsSnapshot(fc) |
| if reflect.DeepEqual(before, after) { |
| return configPath, false, nil |
| } |
| if err := config.SaveFileConfig(fc, configPath); err != nil { |
| return "", false, err |
| } |
| return configPath, true, nil |
| } |
|
|
| func restoreSecurityDefaults() (string, bool, error) { |
| return RestoreSecurityDefaults() |
| } |
|
|
| func RecommendedSecurityDefaultLines(cfg *config.RuntimeConfig) []string { |
| posture := AssessSecurityPosture(cfg) |
| ordered := []string{ |
| "server.bind = 127.0.0.1", |
| "security.allowEvaluate = false", |
| "security.allowMacro = false", |
| "security.allowScreencast = false", |
| "security.allowDownload = false", |
| "security.allowUpload = false", |
| "security.attach.enabled = false", |
| "security.attach.allowHosts = 127.0.0.1,localhost,::1", |
| "security.attach.allowSchemes = ws,wss", |
| "security.idpi.enabled = true", |
| "security.idpi.allowedDomains = 127.0.0.1,localhost,::1", |
| "security.idpi.strictMode = true", |
| "security.idpi.scanContent = true", |
| "security.idpi.wrapContent = true", |
| } |
| needed := make(map[string]bool, len(ordered)) |
|
|
| for _, check := range posture.Checks { |
| if check.Passed { |
| continue |
| } |
| switch check.ID { |
| case "bind_loopback": |
| needed["server.bind = 127.0.0.1"] = true |
| case "sensitive_endpoints_disabled": |
| for _, line := range []string{ |
| "security.allowEvaluate = false", |
| "security.allowMacro = false", |
| "security.allowScreencast = false", |
| "security.allowDownload = false", |
| "security.allowUpload = false", |
| } { |
| needed[line] = true |
| } |
| case "attach_disabled", "attach_local_only": |
| for _, line := range []string{ |
| "security.attach.enabled = false", |
| "security.attach.allowHosts = 127.0.0.1,localhost,::1", |
| "security.attach.allowSchemes = ws,wss", |
| } { |
| needed[line] = true |
| } |
| case "idpi_whitelist_scoped", "idpi_strict_mode", "idpi_content_protection": |
| for _, line := range []string{ |
| "security.idpi.enabled = true", |
| "security.idpi.allowedDomains = 127.0.0.1,localhost,::1", |
| "security.idpi.strictMode = true", |
| "security.idpi.scanContent = true", |
| "security.idpi.wrapContent = true", |
| } { |
| needed[line] = true |
| } |
| } |
| } |
|
|
| lines := make([]string, 0, len(needed)) |
| for _, line := range ordered { |
| if needed[line] { |
| lines = append(lines, line) |
| } |
| } |
| return lines |
| } |
|
|
| type securityDefaultsState struct { |
| Bind string |
| Token string |
| Security securityConfigValues |
| } |
|
|
| type securityConfigValues struct { |
| AllowEvaluate bool |
| AllowMacro bool |
| AllowScreencast bool |
| AllowDownload bool |
| AllowUpload bool |
| MaxRedirects int |
| AttachEnabled bool |
| IDPI config.IDPIConfig |
| } |
|
|
| func securityDefaultsSnapshot(fc *config.FileConfig) securityDefaultsState { |
| if fc == nil { |
| return securityDefaultsState{} |
| } |
| s := securityDefaultsState{ |
| Bind: fc.Server.Bind, |
| Token: fc.Server.Token, |
| Security: securityConfigValues{ |
| IDPI: fc.Security.IDPI, |
| }, |
| } |
| if fc.Security.AllowEvaluate != nil { |
| s.Security.AllowEvaluate = *fc.Security.AllowEvaluate |
| } |
| if fc.Security.AllowMacro != nil { |
| s.Security.AllowMacro = *fc.Security.AllowMacro |
| } |
| if fc.Security.AllowScreencast != nil { |
| s.Security.AllowScreencast = *fc.Security.AllowScreencast |
| } |
| if fc.Security.AllowDownload != nil { |
| s.Security.AllowDownload = *fc.Security.AllowDownload |
| } |
| if fc.Security.AllowUpload != nil { |
| s.Security.AllowUpload = *fc.Security.AllowUpload |
| } |
| if fc.Security.MaxRedirects != nil { |
| s.Security.MaxRedirects = *fc.Security.MaxRedirects |
| } |
| if fc.Security.Attach.Enabled != nil { |
| s.Security.AttachEnabled = *fc.Security.Attach.Enabled |
| } |
| return s |
| } |
|
|