package localserver import ( "bytes" "context" "crypto/x509" "encoding/json" "encoding/pem" "fmt" "io" "log" "net/http" "os" "path/filepath" "time" "github.com/google/uuid" ) var NodeToken string var NodeID string var HTTPClient *http.Client type LocalServerConfig struct { configFilePath string NodeId string `json:"nodeId"` PrivateKeyPath string `json:"privateKeyPath"` Token string `json:"token"` } var configPath = "" var certificatePath = "" func NewLocalServerConfig(appCertificatePath, appConfigPath string) (localServerConfig *LocalServerConfig, err error) { HTTPClient = &http.Client{ Transport: &http.Transport{ DisableKeepAlives: true, MaxIdleConns: 1, MaxIdleConnsPerHost: 1, MaxConnsPerHost: 1, }, Timeout: 10 * time.Second, } configPath = appConfigPath certificatePath = appCertificatePath logFile, err := os.OpenFile(filepath.Join(configPath, "local_server.log"), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755) if err != nil { return } logger.SetOutput(logFile) logger.SetFlags(log.Ldate | log.LUTC | log.Lshortfile | log.Ltime | log.LstdFlags | log.Lmsgprefix) if _, err = os.Stat(filepath.Join(configPath, "config")); err != nil { if os.IsNotExist(err) { if err = os.MkdirAll(filepath.Join(configPath, "config"), 0770); err != nil { return } } else { return } } localServerConfig = &LocalServerConfig{ configFilePath: filepath.Join(configPath, "config", "node_config.json"), } err = localServerConfig.startup() if err != nil { return } err = localServerConfig.authenticate() return } func (l *LocalServerConfig) startup() (err error) { if _, err = os.Stat(l.configFilePath); os.IsNotExist(err) { file, fileErr := os.Create(l.configFilePath) if fileErr != nil { return fileErr } id := uuid.NewString() e := NewEncryptionManager() keypair, keyErr := e.GenerateKeyPair(context.Background(), id, "") if keyErr != nil { return keyErr } baseConfig := map[string]interface{}{ "nodeId": id, "privKeyPath": filepath.Join(configPath, "config", id), "token": "", } bs, marshallErr := json.Marshal(&baseConfig) if marshallErr != nil { return marshallErr } _, writeErr := file.Write(bs) if writeErr != nil { return writeErr } key_bytes := x509.MarshalPKCS1PublicKey(&keypair.PublicKey) key := pem.EncodeToMemory(&pem.Block{ Type: "RSA PUBLIC KEY", Bytes: key_bytes, }) logger.Println(string(key)) l.NodeId = id l.PrivateKeyPath = "" l.Token = "" bss, marshallErr := json.Marshal(map[string]interface{}{ "type": "create_node", "from": id, "to": "serv", "token": "", "peerType": "node", "payload": map[string]string{ "nodeId": id, "nodeKey": string(key), "nodeUsername": "anonymous", }, }) if marshallErr != nil { return marshallErr } res, postErr := HTTPClient.Post("https://dev.zippytal.com/req", "application/json", bytes.NewBuffer(bss)) if postErr != nil { logger.Println("e") return postErr } logger.Println(res) if err = file.Close(); err != nil { return } } else if err != nil { return } file, err := os.Open(l.configFilePath) defer file.Close() if err != nil { return } var config map[string]string err = json.NewDecoder(file).Decode(&config) if err != nil { return } logger.Println(config) NodeID = l.NodeId l.NodeId = config["nodeId"] l.PrivateKeyPath = config["privKeyPath"] l.Token = config["token"] return } func (l *LocalServerConfig) authenticate() (err error) { f, err := os.Open(l.PrivateKeyPath) defer f.Close() if err != nil { return } var buff []byte buff, err = io.ReadAll(f) if err != nil { return } em := NewEncryptionManager() sig, err := em.SignRequest(string(buff), l.NodeId) if err != nil { return } body, err := json.Marshal(map[string]interface{}{ "type": "login_key_node", "from": l.NodeId, "peerType": "node", "payload": map[string]string{ "id": l.NodeId, "signature": sig, }, }) if err != nil { return } res, err := HTTPClient.Post("https://dev.zippytal.com/req", "application/json", bytes.NewBuffer(body)) if err != nil { return } bs, err := io.ReadAll(res.Body) if err != nil { return } var payload map[string]any if err = json.Unmarshal(bs, &payload); err != nil { return } err = l.handleLoginResponse(payload) NodeID = l.NodeId return } func (l *LocalServerConfig) handleLoginResponse(res map[string]any) (err error) { if _, ok := res["token"]; !ok { err = fmt.Errorf("no field token in res") return } if _, ok := res["token"].(string); !ok { err = fmt.Errorf("field token not string in res") return } NodeToken = res["token"].(string) return }