platform: modularize api/gui, add docs-tests-web foundation, and refresh root config

This commit is contained in:
beckline
2026-03-26 22:40:54 +03:00
parent 0e2d7f61ea
commit 6a56d734c2
562 changed files with 70151 additions and 16423 deletions

View File

@@ -0,0 +1,86 @@
package app
import (
"path/filepath"
transportcfgpkg "selective-vpn-api/app/transportcfg"
)
type singBoxSecretsPatchResult struct {
HasSecrets bool
Masked map[string]string
Changed bool
Rollback func()
}
func applySingBoxSecretsPatch(profileID string, clear bool, updates map[string]string) (singBoxSecretsPatchResult, error) {
id := sanitizeID(profileID)
if id == "" {
return singBoxSecretsPatchResult{}, errSingBoxProfileID()
}
prev, err := readSingBoxSecrets(id)
if err != nil {
return singBoxSecretsPatchResult{}, err
}
next := map[string]string{}
if !clear {
next = transportcfgpkg.CloneStringMap(prev)
if next == nil {
next = map[string]string{}
}
}
for key, val := range transportcfgpkg.NormalizeSecretUpdates(updates) {
if val == "" {
delete(next, key)
continue
}
next[key] = val
}
changed := !transportcfgpkg.EqualStringMap(prev, next)
if changed {
if err := writeSingBoxSecrets(id, next); err != nil {
return singBoxSecretsPatchResult{}, err
}
}
res := singBoxSecretsPatchResult{
HasSecrets: len(next) > 0,
Masked: transportcfgpkg.MaskStringMap(next, "******"),
Changed: changed,
}
if changed {
rollbackPrev := transportcfgpkg.CloneStringMap(prev)
res.Rollback = func() {
_ = writeSingBoxSecrets(id, rollbackPrev)
}
}
if !res.HasSecrets {
res.Masked = nil
}
return res, nil
}
func readSingBoxSecrets(profileID string) (map[string]string, error) {
id := sanitizeID(profileID)
if id == "" {
return nil, errSingBoxProfileID()
}
path := singBoxSecretsPath(id)
return transportcfgpkg.ReadStringMapJSON(path)
}
func writeSingBoxSecrets(profileID string, secrets map[string]string) error {
id := sanitizeID(profileID)
if id == "" {
return errSingBoxProfileID()
}
path := singBoxSecretsPath(id)
return transportcfgpkg.WriteStringMapJSON(path, secrets, 0o700, 0o600)
}
func singBoxSecretsPath(profileID string) string {
id := sanitizeID(profileID)
if id == "" {
return filepath.Join(singBoxSecretsRootDir, "invalid.json")
}
return filepath.Join(singBoxSecretsRootDir, id+".json")
}