Spaces:
Paused
Paused
| package handler | |
| import ( | |
| "encoding/json" | |
| "math/rand" | |
| "net/http" | |
| "os" | |
| "strings" | |
| "sync" | |
| ) | |
| type KeyData struct { | |
| Name string `json:"name"` | |
| Key string `json:"key"` | |
| Requests int `json:"requests"` | |
| Tokens int `json:"tokens"` | |
| } | |
| type Store struct { | |
| mu sync.Mutex | |
| Keys map[string]*KeyData `json:"keys"` | |
| } | |
| var s = &Store{Keys: make(map[string]*KeyData)} | |
| const p = "/data/keys.json" | |
| func init() { | |
| os.MkdirAll("/data", 0755) | |
| f, _ := os.ReadFile(p) | |
| if len(f) > 0 { | |
| json.Unmarshal(f, &s) | |
| } else if backup := os.Getenv("BACKUP_KEYS"); backup != "" { | |
| var keys map[string]*KeyData | |
| if json.Unmarshal([]byte(backup), &keys) == nil { | |
| s.Keys = keys | |
| save() | |
| } | |
| } | |
| if s.Keys == nil { | |
| s.Keys = make(map[string]*KeyData) | |
| } | |
| } | |
| func save() { | |
| b, _ := json.MarshalIndent(s, "", " ") | |
| os.WriteFile(p, b, 0644) | |
| } | |
| func TrackUsage(k string, t int) { | |
| if k == "free" { | |
| return | |
| } | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| for _, kd := range s.Keys { | |
| if kd.Key == k { | |
| kd.Tokens += t | |
| save() | |
| return | |
| } | |
| } | |
| } | |
| func CheckAndTrack(k string, t int) (bool, string) { | |
| if strings.HasPrefix(k, "eyJ") { | |
| return true, "" | |
| } | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| for _, kd := range s.Keys { | |
| if kd.Key == k { | |
| kd.Requests++ | |
| kd.Tokens += t | |
| save() | |
| return true, "" | |
| } | |
| } | |
| return false, "Key invalida" | |
| } | |
| func GenerateKey(n string) string { | |
| const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" | |
| b := make([]byte, 8) | |
| for i := range b { | |
| b[i] = chars[rand.Intn(len(chars))] | |
| } | |
| k := "RWPX-" + string(b) | |
| s.mu.Lock() | |
| s.Keys[n+":"+k] = &KeyData{Name: n, Key: k} | |
| s.mu.Unlock() | |
| go func(name, key string) { | |
| BackupKeyToSheet(name, key) | |
| }(n, k) | |
| save() | |
| return k | |
| } | |
| func HandleGenKey(w http.ResponseWriter, r *http.Request) { | |
| n := r.FormValue("name") | |
| if n == "" { | |
| n = "User" | |
| } | |
| existingKey := r.FormValue("key") | |
| var k string | |
| if existingKey != "" { | |
| s.mu.Lock() | |
| s.Keys[n+":"+existingKey] = &KeyData{Name: n, Key: existingKey} | |
| save() | |
| s.mu.Unlock() | |
| go func(name, key string) { | |
| BackupKeyToSheet(name, key) | |
| }(n, existingKey) | |
| k = existingKey | |
| } else { | |
| k = GenerateKey(n) | |
| } | |
| w.Header().Set("Content-Type", "application/json") | |
| resp := map[string]string{"key": k, "name": n} | |
| json.NewEncoder(w).Encode(resp) | |
| } | |
| func HandleDeleteKey(w http.ResponseWriter, r *http.Request) { | |
| if r.URL.Query().Get("token") != "CCCP_IS2_1944_STALIN" { | |
| w.WriteHeader(403) | |
| return | |
| } | |
| k := r.FormValue("key") | |
| if k == "" { | |
| http.Error(w, "key required", 400) | |
| return | |
| } | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| for compositeKey, kd := range s.Keys { | |
| if kd.Key == k { | |
| delete(s.Keys, compositeKey) | |
| save() | |
| break | |
| } | |
| } | |
| w.Write([]byte("OK")) | |
| } | |
| func HandleStats(w http.ResponseWriter, r *http.Request) { | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| w.Header().Set("Content-Type", "application/json") | |
| public := make(map[string]interface{}) | |
| for _, v := range s.Keys { | |
| public[v.Name] = map[string]interface{}{"name": v.Name, "requests": v.Requests} | |
| } | |
| json.NewEncoder(w).Encode(map[string]interface{}{"keys": public}) | |
| } | |
| func HandleSecretReveal(w http.ResponseWriter, r *http.Request) { | |
| if r.URL.Query().Get("token") != "CCCP_IS2_1944_STALIN" { | |
| w.WriteHeader(403) | |
| return | |
| } | |
| s.mu.Lock() | |
| defer s.mu.Unlock() | |
| w.Header().Set("Content-Type", "text/html") | |
| w.Write([]byte("<body style='background:#000;color:#0f0;font-family:monospace;'>")) | |
| for compositeKey := range s.Keys { | |
| w.Write([]byte("<p>" + compositeKey + "</p>")) | |
| } | |
| w.Write([]byte("</body>")) | |
| } |