package content import ( "crypto/tls" "encoding/base64" "fmt" "git.gammaspectra.live/S.O.N.G/FinalCommander/utilities" "git.gammaspectra.live/S.O.N.G/MakyuuIchaival" "git.gammaspectra.live/S.O.N.G/MakyuuIchaival/contentmessage" "github.com/cloudflare/circl/sign/ed25519" "github.com/multiformats/go-multihash" "net/http" "strconv" "strings" "sync" "time" ) type Server struct { Index int Address string Weight uint LastCheckResult bool LastCheckMutex sync.RWMutex } func NewContentServerFromArgument(arg string, index int) (*Server, error) { //Format address:PORT/WEIGHT[/publicKey], p := strings.Split(arg, "/") if len(p) < 2 { return nil, fmt.Errorf("invalid weighted server %s", arg) } weight, err := strconv.ParseUint(p[1], 10, 32) if err != nil { return nil, err } cs := &Server{ Index: index, Address: p[0], Weight: uint(weight), LastCheckResult: false, } return cs, nil } func (s *Server) GetContentURL(content *Entry, key ed25519.PrivateKey, skip []int) string { message := contentmessage.NewContentMessageV1(content.Multihash(), key) skip = append(skip, s.Index) return s.getURL(MakyuuIchaival.Bech32Encoding.EncodeToString(message.Encode()), MakyuuIchaival.Bech32Encoding.EncodeToString(utilities.EncodeIntegerList(skip))) } func (s *Server) GetHashURL(mh multihash.Multihash, key ed25519.PrivateKey, skip []int) string { message := contentmessage.NewContentMessageV1(mh, key) skip = append(skip, s.Index) return s.getURL(MakyuuIchaival.Bech32Encoding.EncodeToString(message.Encode()), MakyuuIchaival.Bech32Encoding.EncodeToString(utilities.EncodeIntegerList(skip))) } func (s *Server) getURL(args ...string) string { return fmt.Sprintf("https://%s/%s", s.Address, strings.Join(args, "/")) } func (s *Server) GetCheckResult() bool { s.LastCheckMutex.RLock() defer s.LastCheckMutex.RUnlock() return s.LastCheckResult } func (s *Server) setCheckResult(result bool) { s.LastCheckMutex.Lock() defer s.LastCheckMutex.Unlock() s.LastCheckResult = result } func (s *Server) Check() { customTransport := http.DefaultTransport.(*http.Transport).Clone() customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} client := &http.Client{ Transport: customTransport, Timeout: 5 * time.Second, } response, err := client.Head(s.getURL()) if err != nil { s.setCheckResult(false) return } defer response.Body.Close() if response.StatusCode != http.StatusBadRequest { s.setCheckResult(false) return } s.setCheckResult(true) } func (s *Server) CheckEntryKey(key *HashIdentifier, privateKey ed25519.PrivateKey) *HashIdentifier { customTransport := http.DefaultTransport.(*http.Transport).Clone() customTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} client := &http.Client{ Transport: customTransport, Timeout: 5 * time.Second, } response, err := client.Head(s.GetHashURL(key.Hash(), privateKey, []int{})) if err != nil { return nil } defer response.Body.Close() if response.StatusCode != http.StatusOK { return nil } v := strings.Split(response.Header.Get("Digest"), "=") if len(v) >= 2 && v[0] == "sha-256" { sha, err := base64.StdEncoding.DecodeString(strings.Join(v[1:], "=")) if err != nil { return nil } mh, err := multihash.Encode(sha, multihash.SHA2_256) if err != nil { return nil } return NewHashIdentifierFromMultihash(mh) } return nil }