115
vendor/github.com/status-im/status-go/server/certs.go
generated
vendored
Normal file
115
vendor/github.com/status-im/status-go/server/certs.go
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
var globalMediaCertificate *tls.Certificate = nil
|
||||
var globalMediaPem string
|
||||
|
||||
func makeRandomSerialNumber() (*big.Int, error) {
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
return rand.Int(rand.Reader, serialNumberLimit)
|
||||
}
|
||||
|
||||
func GenerateX509Cert(sn *big.Int, from, to time.Time, IPAddresses []net.IP, DNSNames []string) *x509.Certificate {
|
||||
return &x509.Certificate{
|
||||
SerialNumber: sn,
|
||||
Subject: pkix.Name{Organization: []string{"Self-signed cert"}},
|
||||
NotBefore: from,
|
||||
NotAfter: to,
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
IPAddresses: IPAddresses,
|
||||
DNSNames: DNSNames,
|
||||
}
|
||||
}
|
||||
|
||||
func GenerateX509PEMs(cert *x509.Certificate, key *ecdsa.PrivateKey) (certPem, keyPem []byte, err error) {
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, &key.PublicKey, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
certPem = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
||||
|
||||
privBytes, err := x509.MarshalPKCS8PrivateKey(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
keyPem = pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GenerateTLSCert(notBefore, notAfter time.Time, IPAddresses []net.IP, DNSNames []string) (*tls.Certificate, []byte, error) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sn, err := makeRandomSerialNumber()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
cert := GenerateX509Cert(sn, notBefore, notAfter, IPAddresses, DNSNames)
|
||||
certPem, keyPem, err := GenerateX509PEMs(cert, priv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
finalCert, err := tls.X509KeyPair(certPem, keyPem)
|
||||
return &finalCert, certPem, err
|
||||
}
|
||||
|
||||
func generateMediaTLSCert() error {
|
||||
if globalMediaCertificate != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
notBefore := now.Add(-365 * 24 * time.Hour * 100)
|
||||
notAfter := now.Add(365 * 24 * time.Hour * 100)
|
||||
log.Debug("generate media cert", "system time", time.Now().String(), "cert notBefore", notBefore.String(), "cert notAfter", notAfter.String())
|
||||
finalCert, certPem, err := GenerateTLSCert(notBefore, notAfter, []net.IP{}, []string{Localhost})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
globalMediaCertificate = finalCert
|
||||
globalMediaPem = string(certPem)
|
||||
return nil
|
||||
}
|
||||
|
||||
func PublicMediaTLSCert() (string, error) {
|
||||
err := generateMediaTLSCert()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return globalMediaPem, nil
|
||||
}
|
||||
|
||||
// ToECDSA takes a []byte of D and uses it to create an ecdsa.PublicKey on the elliptic.P256 curve
|
||||
// this function is basically a P256 curve version of eth-node/crypto.ToECDSA without all the nice validation
|
||||
func ToECDSA(d []byte) *ecdsa.PrivateKey {
|
||||
k := new(ecdsa.PrivateKey)
|
||||
k.D = new(big.Int).SetBytes(d)
|
||||
k.PublicKey.Curve = elliptic.P256()
|
||||
|
||||
k.PublicKey.X, k.PublicKey.Y = k.PublicKey.Curve.ScalarBaseMult(d)
|
||||
return k
|
||||
}
|
||||
34
vendor/github.com/status-im/status-go/server/device.go
generated
vendored
Normal file
34
vendor/github.com/status-im/status-go/server/device.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
local = ".local"
|
||||
)
|
||||
|
||||
func RemoveSuffix(input, suffix string) string {
|
||||
il := len(input)
|
||||
sl := len(suffix)
|
||||
if il > sl {
|
||||
if input[il-sl:] == suffix {
|
||||
return input[:il-sl]
|
||||
}
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
func parseHostname(hostname string) string {
|
||||
hostname = RemoveSuffix(hostname, local)
|
||||
return strings.ReplaceAll(hostname, "-", " ")
|
||||
}
|
||||
|
||||
func GetDeviceName() (string, error) {
|
||||
name, err := os.Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return parseHostname(name), nil
|
||||
}
|
||||
1154
vendor/github.com/status-im/status-go/server/handlers.go
generated
vendored
Normal file
1154
vendor/github.com/status-im/status-go/server/handlers.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
209
vendor/github.com/status-im/status-go/server/handlers_linkpreview.go
generated
vendored
Normal file
209
vendor/github.com/status-im/status-go/server/handlers_linkpreview.go
generated
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/images"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/protocol/protobuf"
|
||||
)
|
||||
|
||||
func getThumbnailPayload(db *sql.DB, logger *zap.Logger, msgID string, thumbnailURL string) ([]byte, error) {
|
||||
var payload []byte
|
||||
|
||||
var result []byte
|
||||
err := db.QueryRow(`SELECT unfurled_links FROM user_messages WHERE id = ?`, msgID).Scan(&result)
|
||||
if err != nil {
|
||||
return payload, fmt.Errorf("could not find message with message-id '%s': %w", msgID, err)
|
||||
}
|
||||
|
||||
var links []*protobuf.UnfurledLink
|
||||
err = json.Unmarshal(result, &links)
|
||||
if err != nil {
|
||||
return payload, fmt.Errorf("failed to unmarshal protobuf.UrlPreview: %w", err)
|
||||
}
|
||||
|
||||
for _, p := range links {
|
||||
if p.Url == thumbnailURL {
|
||||
payload = p.ThumbnailPayload
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func handleLinkPreviewThumbnail(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
params := r.URL.Query()
|
||||
parsed := ParseImageParams(logger, params)
|
||||
|
||||
if parsed.MessageID == "" {
|
||||
http.Error(w, "missing query parameter 'message-id'", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if parsed.URL == "" {
|
||||
http.Error(w, "missing query parameter 'url'", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
thumbnail, err := getThumbnailPayload(db, logger, parsed.MessageID, parsed.URL)
|
||||
if err != nil {
|
||||
logger.Error("failed to get thumbnail", zap.String("msgID", parsed.MessageID))
|
||||
http.Error(w, "failed to get thumbnail", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
mimeType, err := images.GetMimeType(thumbnail)
|
||||
if err != nil {
|
||||
http.Error(w, "mime type not supported", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "image/"+mimeType)
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
|
||||
_, err = w.Write(thumbnail)
|
||||
if err != nil {
|
||||
logger.Error("failed to write response", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getStatusLinkPreviewImage(p *protobuf.UnfurledStatusLink, imageID common.MediaServerImageID) ([]byte, error) {
|
||||
|
||||
switch imageID {
|
||||
case common.MediaServerContactIcon:
|
||||
contact := p.GetContact()
|
||||
if contact == nil {
|
||||
return nil, fmt.Errorf("this is not a contact link")
|
||||
}
|
||||
if contact.Icon == nil {
|
||||
return nil, fmt.Errorf("contact icon is empty")
|
||||
}
|
||||
return contact.Icon.Payload, nil
|
||||
|
||||
case common.MediaServerCommunityIcon:
|
||||
community := p.GetCommunity()
|
||||
if community == nil {
|
||||
return nil, fmt.Errorf("this is not a community link")
|
||||
}
|
||||
if community.Icon == nil {
|
||||
return nil, fmt.Errorf("community icon is empty")
|
||||
}
|
||||
return community.Icon.Payload, nil
|
||||
|
||||
case common.MediaServerCommunityBanner:
|
||||
community := p.GetCommunity()
|
||||
if community == nil {
|
||||
return nil, fmt.Errorf("this is not a community link")
|
||||
}
|
||||
if community.Banner == nil {
|
||||
return nil, fmt.Errorf("community banner is empty")
|
||||
}
|
||||
return community.Banner.Payload, nil
|
||||
|
||||
case common.MediaServerChannelCommunityIcon:
|
||||
channel := p.GetChannel()
|
||||
if channel == nil {
|
||||
return nil, fmt.Errorf("this is not a community channel link")
|
||||
}
|
||||
if channel.Community == nil {
|
||||
return nil, fmt.Errorf("channel community is empty")
|
||||
}
|
||||
if channel.Community.Icon == nil {
|
||||
return nil, fmt.Errorf("channel community icon is empty")
|
||||
}
|
||||
return channel.Community.Icon.Payload, nil
|
||||
|
||||
case common.MediaServerChannelCommunityBanner:
|
||||
channel := p.GetChannel()
|
||||
if channel == nil {
|
||||
return nil, fmt.Errorf("this is not a community channel link")
|
||||
}
|
||||
if channel.Community == nil {
|
||||
return nil, fmt.Errorf("channel community is empty")
|
||||
}
|
||||
if channel.Community.Banner == nil {
|
||||
return nil, fmt.Errorf("channel community banner is empty")
|
||||
}
|
||||
return channel.Community.Banner.Payload, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("value not supported")
|
||||
}
|
||||
|
||||
func getStatusLinkPreviewThumbnail(db *sql.DB, messageID string, URL string, imageID common.MediaServerImageID) ([]byte, int, error) {
|
||||
var messageLinks []byte
|
||||
err := db.QueryRow(`SELECT unfurled_status_links FROM user_messages WHERE id = ?`, messageID).Scan(&messageLinks)
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, fmt.Errorf("could not find message with message-id '%s': %w", messageID, err)
|
||||
}
|
||||
|
||||
var links protobuf.UnfurledStatusLinks
|
||||
err = proto.Unmarshal(messageLinks, &links)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, fmt.Errorf("failed to unmarshal protobuf.UrlPreview: %w", err)
|
||||
}
|
||||
|
||||
for _, p := range links.UnfurledStatusLinks {
|
||||
if p.Url == URL {
|
||||
thumbnailPayload, err := getStatusLinkPreviewImage(p, imageID)
|
||||
if err != nil {
|
||||
return nil, http.StatusBadRequest, fmt.Errorf("invalid query parameter 'image-id' value: %w", err)
|
||||
}
|
||||
return thumbnailPayload, http.StatusOK, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, http.StatusBadRequest, fmt.Errorf("no link preview found for given url")
|
||||
}
|
||||
|
||||
func handleStatusLinkPreviewThumbnail(db *sql.DB, logger *zap.Logger) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
params := r.URL.Query()
|
||||
parsed := ParseImageParams(logger, params)
|
||||
|
||||
if parsed.MessageID == "" {
|
||||
http.Error(w, "missing query parameter 'message-id'", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if parsed.URL == "" {
|
||||
http.Error(w, "missing query parameter 'url'", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if parsed.ImageID == "" {
|
||||
http.Error(w, "missing query parameter 'image-id'", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
thumbnail, httpsStatusCode, err := getStatusLinkPreviewThumbnail(db, parsed.MessageID, parsed.URL, common.MediaServerImageID(parsed.ImageID))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), httpsStatusCode)
|
||||
return
|
||||
}
|
||||
|
||||
mimeType, err := images.GetMimeType(thumbnail)
|
||||
if err != nil {
|
||||
http.Error(w, "mime type not supported", http.StatusNotImplemented)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "image/"+mimeType)
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
|
||||
_, err = w.Write(thumbnail)
|
||||
if err != nil {
|
||||
logger.Error("failed to write response", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
203
vendor/github.com/status-im/status-go/server/ips.go
generated
vendored
Normal file
203
vendor/github.com/status-im/status-go/server/ips.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/common"
|
||||
"github.com/status-im/status-go/logutils"
|
||||
)
|
||||
|
||||
var (
|
||||
LocalHostIP = net.IP{127, 0, 0, 1}
|
||||
Localhost = "Localhost"
|
||||
)
|
||||
|
||||
func GetOutboundIP() (net.IP, error) {
|
||||
conn, err := net.Dial("udp", "255.255.255.255:8080")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
||||
|
||||
return localAddr.IP, nil
|
||||
}
|
||||
|
||||
// addrToIPNet casts addr to IPNet.
|
||||
// Returns nil if addr is not of IPNet type.
|
||||
func addrToIPNet(addr net.Addr) *net.IPNet {
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
return v
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// filterAddressesForPairingServer filters private unicast addresses.
|
||||
// ips is a 2-dimensional array, where each sub-array is a list of IP
|
||||
// addresses for a single network interface.
|
||||
func filterAddressesForPairingServer(ips [][]net.IP) []net.IP {
|
||||
var result = map[string]net.IP{}
|
||||
|
||||
for _, niIps := range ips {
|
||||
var ipv4, ipv6 []net.IP
|
||||
|
||||
for _, ip := range niIps {
|
||||
|
||||
// Only take private global unicast addrs
|
||||
if !ip.IsGlobalUnicast() || !ip.IsPrivate() {
|
||||
continue
|
||||
}
|
||||
|
||||
if v := ip.To4(); v != nil {
|
||||
ipv4 = append(ipv4, ip)
|
||||
} else {
|
||||
ipv6 = append(ipv6, ip)
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer IPv4 over IPv6 for shorter connection string
|
||||
if len(ipv4) == 0 {
|
||||
for _, ip := range ipv6 {
|
||||
result[ip.String()] = ip
|
||||
}
|
||||
} else {
|
||||
for _, ip := range ipv4 {
|
||||
result[ip.String()] = ip
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var out []net.IP
|
||||
for _, v := range result {
|
||||
out = append(out, v)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// getAndroidLocalIP uses the net dial default ip as the standard Android IP address
|
||||
// patches https://github.com/status-im/status-mobile/issues/17156
|
||||
// more work required for a more robust implementation, see https://github.com/wlynxg/anet
|
||||
func getAndroidLocalIP() ([][]net.IP, error) {
|
||||
ip, err := GetOutboundIP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return [][]net.IP{{ip}}, nil
|
||||
}
|
||||
|
||||
// getLocalAddresses returns an array of all addresses
|
||||
// of all available network interfaces.
|
||||
func getLocalAddresses() ([][]net.IP, error) {
|
||||
// TODO until we can resolve Android errors when calling net.Interfaces() just return the outbound local address.
|
||||
// Sorry Android
|
||||
if common.OperatingSystemIs(common.AndroidPlatform) {
|
||||
return getAndroidLocalIP()
|
||||
}
|
||||
|
||||
nis, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ips [][]net.IP
|
||||
|
||||
for _, ni := range nis {
|
||||
var niIps []net.IP
|
||||
|
||||
addrs, err := ni.Addrs()
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Warn("failed to get addresses of network interface",
|
||||
zap.String("networkInterface", ni.Name),
|
||||
zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
if ipNet := addrToIPNet(addr); ipNet == nil {
|
||||
continue
|
||||
} else {
|
||||
ip = ipNet.IP
|
||||
}
|
||||
niIps = append(niIps, ip)
|
||||
}
|
||||
|
||||
if len(niIps) > 0 {
|
||||
ips = append(ips, niIps)
|
||||
}
|
||||
}
|
||||
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
// GetLocalAddressesForPairingServer is a high-level func
|
||||
// that returns a list of addresses to be used by local pairing server.
|
||||
func GetLocalAddressesForPairingServer() ([]net.IP, error) {
|
||||
ips, err := getLocalAddresses()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return filterAddressesForPairingServer(ips), nil
|
||||
}
|
||||
|
||||
// findReachableAddresses returns a filtered remoteIps array,
|
||||
// in which each IP matches one or more of given localNets.
|
||||
func findReachableAddresses(remoteIPs []net.IP, localNets []net.IPNet) []net.IP {
|
||||
var result []net.IP
|
||||
for _, localNet := range localNets {
|
||||
for _, remoteIP := range remoteIPs {
|
||||
if localNet.Contains(remoteIP) {
|
||||
result = append(result, remoteIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// getAllAvailableNetworks collects all networks
|
||||
// from available network interfaces.
|
||||
func getAllAvailableNetworks() ([]net.IPNet, error) {
|
||||
var localNets []net.IPNet
|
||||
|
||||
nis, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ni := range nis {
|
||||
addrs, err := ni.Addrs()
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Warn("failed to get addresses of network interface",
|
||||
zap.String("networkInterface", ni.Name),
|
||||
zap.Error(err))
|
||||
continue
|
||||
}
|
||||
|
||||
for _, localAddr := range addrs {
|
||||
localNets = append(localNets, *addrToIPNet(localAddr))
|
||||
}
|
||||
}
|
||||
return localNets, nil
|
||||
}
|
||||
|
||||
// FindReachableAddressesForPairingClient is a high-level func
|
||||
// that returns a reachable server's address to be used by local pairing client.
|
||||
func FindReachableAddressesForPairingClient(serverIps []net.IP) ([]net.IP, error) {
|
||||
// TODO until we can resolve Android errors when calling net.Interfaces() just noop. Sorry Android
|
||||
if common.OperatingSystemIs(common.AndroidPlatform) {
|
||||
return serverIps, nil
|
||||
}
|
||||
|
||||
nets, err := getAllAvailableNetworks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return findReachableAddresses(serverIps, nets), nil
|
||||
}
|
||||
93
vendor/github.com/status-im/status-go/server/pairing/statecontrol/state_management.go
generated
vendored
Normal file
93
vendor/github.com/status-im/status-go/server/pairing/statecontrol/state_management.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package statecontrol
|
||||
|
||||
// TODO refactor into the pairing package once the backend dependencies have been removed.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrProcessStateManagerAlreadyPairing = fmt.Errorf("cannot start new LocalPairing session, already pairing")
|
||||
ErrProcessStateManagerAlreadyPaired = func(sessionName string) error {
|
||||
return fmt.Errorf("given connection string already successfully used '%s'", sessionName)
|
||||
}
|
||||
)
|
||||
|
||||
// ProcessStateManager represents a g
|
||||
type ProcessStateManager struct {
|
||||
pairing bool
|
||||
pairingLock sync.Mutex
|
||||
|
||||
// sessions represents a map[string]bool:
|
||||
// where string is a ConnectionParams string and bool is the transfer success state of that connection string
|
||||
sessions sync.Map
|
||||
}
|
||||
|
||||
// IsPairing returns if the ProcessStateManager is currently in pairing mode
|
||||
func (psm *ProcessStateManager) IsPairing() bool {
|
||||
psm.pairingLock.Lock()
|
||||
defer psm.pairingLock.Unlock()
|
||||
return psm.pairing
|
||||
}
|
||||
|
||||
// SetPairing sets the ProcessStateManager pairing state
|
||||
func (psm *ProcessStateManager) SetPairing(state bool) {
|
||||
psm.pairingLock.Lock()
|
||||
defer psm.pairingLock.Unlock()
|
||||
psm.pairing = state
|
||||
}
|
||||
|
||||
// RegisterSession stores a sessionName with the default false value.
|
||||
// In practice a sessionName will be a ConnectionParams string provided by the server mode device.
|
||||
// The boolean value represents whether the ConnectionParams string session resulted in a successful transfer.
|
||||
func (psm *ProcessStateManager) RegisterSession(sessionName string) {
|
||||
psm.sessions.Store(sessionName, false)
|
||||
}
|
||||
|
||||
// CompleteSession updates a transfer session with a given transfer success state only if the session is registered.
|
||||
func (psm *ProcessStateManager) CompleteSession(sessionName string) {
|
||||
r, c := psm.GetSession(sessionName)
|
||||
if r && !c {
|
||||
psm.sessions.Store(sessionName, true)
|
||||
}
|
||||
}
|
||||
|
||||
// GetSession returns two booleans for a given sessionName.
|
||||
// These represent if the sessionName has been registered and if it has resulted in a successful transfer
|
||||
func (psm *ProcessStateManager) GetSession(sessionName string) (bool, bool) {
|
||||
completed, registered := psm.sessions.Load(sessionName)
|
||||
if !registered {
|
||||
return registered, false
|
||||
}
|
||||
return registered, completed.(bool)
|
||||
}
|
||||
|
||||
// StartPairing along with StopPairing are the core functions of the ProcessStateManager
|
||||
// This function takes a sessionName, which in practice is a ConnectionParams string, and attempts to init pairing state management.
|
||||
// The function will return an error if the ProcessStateManager is already currently pairing or if the sessionName was previously successful.
|
||||
func (psm *ProcessStateManager) StartPairing(sessionName string) error {
|
||||
if psm.IsPairing() {
|
||||
return ErrProcessStateManagerAlreadyPairing
|
||||
}
|
||||
|
||||
registered, completed := psm.GetSession(sessionName)
|
||||
if completed {
|
||||
return ErrProcessStateManagerAlreadyPaired(sessionName)
|
||||
}
|
||||
if !registered {
|
||||
psm.RegisterSession(sessionName)
|
||||
}
|
||||
|
||||
psm.SetPairing(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopPairing takes a sessionName and an error, if the error is nil the sessionName will be recorded as successful
|
||||
// the pairing state of the ProcessStateManager is set to false.
|
||||
func (psm *ProcessStateManager) StopPairing(sessionName string, err error) {
|
||||
if err == nil {
|
||||
psm.CompleteSession(sessionName)
|
||||
}
|
||||
psm.SetPairing(false)
|
||||
}
|
||||
80
vendor/github.com/status-im/status-go/server/ports.go
generated
vendored
Normal file
80
vendor/github.com/status-im/status-go/server/ports.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// portManager is responsible for maintaining segregated access to the port field
|
||||
type portManger struct {
|
||||
logger *zap.Logger
|
||||
port int
|
||||
afterPortChanged func(port int)
|
||||
}
|
||||
|
||||
// newPortManager returns a newly initialised portManager
|
||||
func newPortManager(logger *zap.Logger, afterPortChanged func(int)) portManger {
|
||||
pm := portManger{
|
||||
logger: logger.Named("portManger"),
|
||||
afterPortChanged: afterPortChanged,
|
||||
}
|
||||
return pm
|
||||
}
|
||||
|
||||
// SetPort sets portManger.port field to the given port value
|
||||
// next triggers any given portManger.afterPortChanged function
|
||||
func (p *portManger) SetPort(port int) error {
|
||||
l := p.logger.Named("SetPort")
|
||||
l.Debug("fired", zap.Int("port", port))
|
||||
|
||||
if port == 0 {
|
||||
errMsg := "port can not be `0`, use ResetPort() instead"
|
||||
l.Error(errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
}
|
||||
|
||||
p.port = port
|
||||
if p.afterPortChanged != nil {
|
||||
l.Debug("p.afterPortChanged != nil")
|
||||
p.afterPortChanged(port)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetPort resets portManger.port to 0
|
||||
func (p *portManger) ResetPort() {
|
||||
l := p.logger.Named("ResetPort")
|
||||
l.Debug("fired")
|
||||
|
||||
p.port = 0
|
||||
}
|
||||
|
||||
// GetPort gets the current value of portManager.port without any concern for the state of its value
|
||||
// and therefore does not wait if portManager.port is 0
|
||||
func (p *portManger) GetPort() int {
|
||||
l := p.logger.Named("GetPort")
|
||||
l.Debug("fired")
|
||||
|
||||
return p.port
|
||||
}
|
||||
|
||||
// MustGetPort only returns portManager.port if portManager.port is not 0.
|
||||
func (p *portManger) MustGetPort() int {
|
||||
l := p.logger.Named("MustGetPort")
|
||||
l.Debug("fired")
|
||||
|
||||
for {
|
||||
if p.port != 0 {
|
||||
port := p.port
|
||||
if port == 0 {
|
||||
panic("port is zero, port has reset")
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
l.Debug("port is zero")
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
306
vendor/github.com/status-im/status-go/server/qrops.go
generated
vendored
Normal file
306
vendor/github.com/status-im/status-go/server/qrops.go
generated
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/yeqown/go-qrcode/v2"
|
||||
"github.com/yeqown/go-qrcode/writer/standard"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/images"
|
||||
"github.com/status-im/status-go/multiaccounts"
|
||||
)
|
||||
|
||||
type WriterCloserByteBuffer struct {
|
||||
*bytes.Buffer
|
||||
}
|
||||
|
||||
func (wc WriterCloserByteBuffer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewWriterCloserByteBuffer() *WriterCloserByteBuffer {
|
||||
return &WriterCloserByteBuffer{bytes.NewBuffer([]byte{})}
|
||||
}
|
||||
|
||||
type QRConfig struct {
|
||||
DecodedQRURL string
|
||||
WithLogo bool
|
||||
CorrectionLevel qrcode.EncodeOption
|
||||
KeyUID string
|
||||
ImageName string
|
||||
Size int
|
||||
Params url.Values
|
||||
}
|
||||
|
||||
func NewQRConfig(params url.Values, logger *zap.Logger) (*QRConfig, error) {
|
||||
config := &QRConfig{}
|
||||
config.Params = params
|
||||
err := config.setQrURL()
|
||||
|
||||
if err != nil {
|
||||
logger.Error("[qrops-error] error in setting QRURL", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.setAllowProfileImage()
|
||||
config.setErrorCorrectionLevel()
|
||||
err = config.setSize()
|
||||
|
||||
if err != nil {
|
||||
logger.Error("[qrops-error] could not convert string to int for size param ", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.WithLogo {
|
||||
err = config.setKeyUID()
|
||||
|
||||
if err != nil {
|
||||
logger.Error(err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.setImageName()
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (q *QRConfig) setQrURL() error {
|
||||
qrURL, ok := q.Params["url"]
|
||||
|
||||
if !ok || len(qrURL) == 0 {
|
||||
return errors.New("[qrops-error] no qr url provided")
|
||||
}
|
||||
|
||||
decodedURL, err := base64.StdEncoding.DecodeString(qrURL[0])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
q.DecodedQRURL = string(decodedURL)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *QRConfig) setAllowProfileImage() {
|
||||
allowProfileImage, ok := q.Params["allowProfileImage"]
|
||||
|
||||
if !ok || len(allowProfileImage) == 0 {
|
||||
// we default to false when this flag was not provided
|
||||
// so someone does not want to allowProfileImage on their QR Image
|
||||
// fine then :)
|
||||
q.WithLogo = false
|
||||
}
|
||||
|
||||
LogoOnImage, err := strconv.ParseBool(allowProfileImage[0])
|
||||
|
||||
if err != nil {
|
||||
// maybe for fun someone tries to send non-boolean values to this flag
|
||||
// we also default to false in that case
|
||||
q.WithLogo = false
|
||||
}
|
||||
|
||||
// if we reach here its most probably true
|
||||
q.WithLogo = LogoOnImage
|
||||
}
|
||||
|
||||
func (q *QRConfig) setErrorCorrectionLevel() {
|
||||
level, ok := q.Params["level"]
|
||||
if !ok || len(level) == 0 {
|
||||
// we default to MediumLevel of error correction when the level flag
|
||||
// is not passed.
|
||||
q.CorrectionLevel = qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionMedium)
|
||||
}
|
||||
|
||||
levelInt, err := strconv.Atoi(level[0])
|
||||
if err != nil || levelInt < 0 {
|
||||
// if there is any issue with string to int conversion
|
||||
// we still default to MediumLevel of error correction
|
||||
q.CorrectionLevel = qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionMedium)
|
||||
}
|
||||
|
||||
switch levelInt {
|
||||
case 1:
|
||||
q.CorrectionLevel = qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionLow)
|
||||
case 2:
|
||||
q.CorrectionLevel = qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionMedium)
|
||||
case 3:
|
||||
q.CorrectionLevel = qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionQuart)
|
||||
case 4:
|
||||
q.CorrectionLevel = qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionHighest)
|
||||
default:
|
||||
q.CorrectionLevel = qrcode.WithErrorCorrectionLevel(qrcode.ErrorCorrectionMedium)
|
||||
}
|
||||
}
|
||||
|
||||
func (q *QRConfig) setSize() error {
|
||||
size, ok := q.Params["size"]
|
||||
|
||||
if ok {
|
||||
imageToBeResized, err := strconv.Atoi(size[0])
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if imageToBeResized <= 0 {
|
||||
return errors.New("[qrops-error] Got an invalid size parameter, it should be greater than zero")
|
||||
}
|
||||
|
||||
q.Size = imageToBeResized
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *QRConfig) setKeyUID() error {
|
||||
keyUID, ok := q.Params["keyUid"]
|
||||
// the keyUID was not passed, which is a requirement to get the multiaccount image,
|
||||
// so we log this error
|
||||
if !ok || len(keyUID) == 0 {
|
||||
return errors.New("[qrops-error] A keyUID is required to put logo on image and it was not passed in the parameters")
|
||||
}
|
||||
|
||||
q.KeyUID = keyUID[0]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *QRConfig) setImageName() {
|
||||
imageName, ok := q.Params["imageName"]
|
||||
//if the imageName was not passed, we default to const images.LargeDimName
|
||||
if !ok || len(imageName) == 0 {
|
||||
q.ImageName = images.LargeDimName
|
||||
}
|
||||
|
||||
q.ImageName = imageName[0]
|
||||
}
|
||||
|
||||
func ToLogoImageFromBytes(imageBytes []byte, padding int) ([]byte, error) {
|
||||
img, _, err := image.Decode(bytes.NewReader(imageBytes))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("decoding image failed: %v", err)
|
||||
}
|
||||
circle := images.CreateCircleWithPadding(img, padding)
|
||||
resultBytes, err := images.EncodePNG(circle)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("encoding PNG failed: %v", err)
|
||||
}
|
||||
return resultBytes, nil
|
||||
}
|
||||
|
||||
func GetLogoImage(multiaccountsDB *multiaccounts.Database, keyUID string, imageName string) ([]byte, error) {
|
||||
var (
|
||||
padding int
|
||||
LogoBytes []byte
|
||||
)
|
||||
|
||||
staticImageData, err := images.Asset("_assets/tests/qr/status.png")
|
||||
if err != nil { // Asset was not found.
|
||||
return nil, err
|
||||
}
|
||||
identityImageObjectFromDB, err := multiaccountsDB.GetIdentityImage(keyUID, imageName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// default padding to 10 to make the QR with profile image look as per
|
||||
// the designs
|
||||
padding = 10
|
||||
|
||||
if identityImageObjectFromDB == nil {
|
||||
LogoBytes, err = ToLogoImageFromBytes(staticImageData, padding)
|
||||
} else {
|
||||
LogoBytes, err = ToLogoImageFromBytes(identityImageObjectFromDB.Payload, padding)
|
||||
}
|
||||
|
||||
return LogoBytes, err
|
||||
}
|
||||
|
||||
func GetPadding(imgBytes []byte) int {
|
||||
const (
|
||||
defaultPadding = 20
|
||||
)
|
||||
size, _, err := images.GetImageDimensions(imgBytes)
|
||||
if err != nil {
|
||||
return defaultPadding
|
||||
}
|
||||
return size / 5
|
||||
}
|
||||
|
||||
func generateQRBytes(params url.Values, logger *zap.Logger, multiaccountsDB *multiaccounts.Database) []byte {
|
||||
|
||||
qrGenerationConfig, err := NewQRConfig(params, logger)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("could not generate QRConfig please rectify the errors with input parameters", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
qrc, err := qrcode.NewWith(qrGenerationConfig.DecodedQRURL,
|
||||
qrcode.WithEncodingMode(qrcode.EncModeAuto),
|
||||
qrGenerationConfig.CorrectionLevel,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("could not generate QRCode with provided options", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
buf := NewWriterCloserByteBuffer()
|
||||
nw := standard.NewWithWriter(buf)
|
||||
err = qrc.Save(nw)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("could not save image", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
payload := buf.Bytes()
|
||||
|
||||
if qrGenerationConfig.WithLogo {
|
||||
logo, err := GetLogoImage(multiaccountsDB, qrGenerationConfig.KeyUID, qrGenerationConfig.ImageName)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("could not get logo image from multiaccountsDB", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
qrWidth, qrHeight, err := images.GetImageDimensions(payload)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("could not get image dimensions from payload", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
logo, err = images.ResizeImage(logo, qrWidth/5, qrHeight/5)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("could not resize logo image ", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
|
||||
payload = images.SuperimposeLogoOnQRImage(payload, logo)
|
||||
}
|
||||
|
||||
if qrGenerationConfig.Size > 0 {
|
||||
|
||||
payload, err = images.ResizeImage(payload, qrGenerationConfig.Size, qrGenerationConfig.Size)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("could not resize final logo image ", zap.Error(err))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return payload
|
||||
|
||||
}
|
||||
174
vendor/github.com/status-im/status-go/server/server.go
generated
vendored
Normal file
174
vendor/github.com/status-im/status-go/server/server.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
isRunning bool
|
||||
server *http.Server
|
||||
logger *zap.Logger
|
||||
cert *tls.Certificate
|
||||
hostname string
|
||||
handlers HandlerPatternMap
|
||||
|
||||
portManger
|
||||
*timeoutManager
|
||||
}
|
||||
|
||||
func NewServer(cert *tls.Certificate, hostname string, afterPortChanged func(int), logger *zap.Logger) Server {
|
||||
return Server{
|
||||
logger: logger,
|
||||
cert: cert,
|
||||
hostname: hostname,
|
||||
portManger: newPortManager(logger.Named("Server"), afterPortChanged),
|
||||
timeoutManager: newTimeoutManager(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) getHost() string {
|
||||
return fmt.Sprintf("%s:%d", s.hostname, s.GetPort())
|
||||
}
|
||||
|
||||
func (s *Server) GetHostname() string {
|
||||
return s.hostname
|
||||
}
|
||||
|
||||
func (s *Server) GetCert() *tls.Certificate {
|
||||
return s.cert
|
||||
}
|
||||
|
||||
func (s *Server) GetLogger() *zap.Logger {
|
||||
return s.logger
|
||||
}
|
||||
|
||||
func (s *Server) mustGetHost() string {
|
||||
return fmt.Sprintf("%s:%d", s.hostname, s.MustGetPort())
|
||||
}
|
||||
|
||||
func (s *Server) listenAndServe() {
|
||||
cfg := &tls.Config{Certificates: []tls.Certificate{*s.cert}, ServerName: s.hostname, MinVersion: tls.VersionTLS12}
|
||||
|
||||
// in case of restart, we should use the same port as the first start in order not to break existing links
|
||||
listener, err := tls.Listen("tcp", s.getHost(), cfg)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to start server, retrying", zap.Error(err))
|
||||
s.ResetPort()
|
||||
err = s.Start()
|
||||
if err != nil {
|
||||
s.logger.Error("server start failed, giving up", zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = s.SetPort(listener.Addr().(*net.TCPAddr).Port)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to set Server.port", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
s.isRunning = true
|
||||
|
||||
s.StartTimeout(func() {
|
||||
err := s.Stop()
|
||||
if err != nil {
|
||||
s.logger.Error("server termination fail", zap.Error(err))
|
||||
}
|
||||
})
|
||||
|
||||
err = s.server.Serve(listener)
|
||||
if err != http.ErrServerClosed {
|
||||
s.logger.Error("server failed unexpectedly, restarting", zap.Error(err))
|
||||
err = s.Start()
|
||||
if err != nil {
|
||||
s.logger.Error("server start failed, giving up", zap.Error(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
s.isRunning = false
|
||||
}
|
||||
|
||||
func (s *Server) resetServer() {
|
||||
s.StopTimeout()
|
||||
s.server = new(http.Server)
|
||||
s.ResetPort()
|
||||
}
|
||||
|
||||
func (s *Server) applyHandlers() {
|
||||
if s.server == nil {
|
||||
s.server = new(http.Server)
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
|
||||
for p, h := range s.handlers {
|
||||
mux.HandleFunc(p, h)
|
||||
}
|
||||
s.server.Handler = mux
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
// Once Shutdown has been called on a server, it may not be reused;
|
||||
s.resetServer()
|
||||
s.applyHandlers()
|
||||
go s.listenAndServe()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Stop() error {
|
||||
s.StopTimeout()
|
||||
if s.server != nil {
|
||||
return s.server.Shutdown(context.Background())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) IsRunning() bool {
|
||||
return s.isRunning
|
||||
}
|
||||
|
||||
func (s *Server) ToForeground() {
|
||||
if !s.isRunning && (s.server != nil) {
|
||||
err := s.Start()
|
||||
if err != nil {
|
||||
s.logger.Error("server start failed during foreground transition", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) ToBackground() {
|
||||
if s.isRunning {
|
||||
err := s.Stop()
|
||||
if err != nil {
|
||||
s.logger.Error("server stop failed during background transition", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) SetHandlers(handlers HandlerPatternMap) {
|
||||
s.handlers = handlers
|
||||
}
|
||||
|
||||
func (s *Server) AddHandlers(handlers HandlerPatternMap) {
|
||||
if s.handlers == nil {
|
||||
s.handlers = make(HandlerPatternMap)
|
||||
}
|
||||
|
||||
for name := range handlers {
|
||||
s.handlers[name] = handlers[name]
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) MakeBaseURL() *url.URL {
|
||||
return &url.URL{
|
||||
Scheme: "https",
|
||||
Host: s.mustGetHost(),
|
||||
}
|
||||
}
|
||||
194
vendor/github.com/status-im/status-go/server/server_media.go
generated
vendored
Normal file
194
vendor/github.com/status-im/status-go/server/server_media.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/status-im/status-go/ipfs"
|
||||
"github.com/status-im/status-go/logutils"
|
||||
"github.com/status-im/status-go/multiaccounts"
|
||||
"github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/services/wallet/thirdparty"
|
||||
"github.com/status-im/status-go/signal"
|
||||
)
|
||||
|
||||
type MediaServer struct {
|
||||
Server
|
||||
|
||||
db *sql.DB
|
||||
downloader *ipfs.Downloader
|
||||
multiaccountsDB *multiaccounts.Database
|
||||
walletDB *sql.DB
|
||||
}
|
||||
|
||||
// NewMediaServer returns a *MediaServer
|
||||
func NewMediaServer(db *sql.DB, downloader *ipfs.Downloader, multiaccountsDB *multiaccounts.Database, walletDB *sql.DB) (*MediaServer, error) {
|
||||
err := generateMediaTLSCert()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &MediaServer{
|
||||
Server: NewServer(
|
||||
globalMediaCertificate,
|
||||
Localhost,
|
||||
signal.SendMediaServerStarted,
|
||||
logutils.ZapLogger().Named("MediaServer"),
|
||||
),
|
||||
db: db,
|
||||
downloader: downloader,
|
||||
multiaccountsDB: multiaccountsDB,
|
||||
walletDB: walletDB,
|
||||
}
|
||||
s.SetHandlers(HandlerPatternMap{
|
||||
accountImagesPath: handleAccountImages(s.multiaccountsDB, s.logger),
|
||||
accountInitialsPath: handleAccountInitials(s.multiaccountsDB, s.logger),
|
||||
audioPath: handleAudio(s.db, s.logger),
|
||||
contactImagesPath: handleContactImages(s.db, s.logger),
|
||||
discordAttachmentsPath: handleDiscordAttachment(s.db, s.logger),
|
||||
discordAuthorsPath: handleDiscordAuthorAvatar(s.db, s.logger),
|
||||
generateQRCode: handleQRCodeGeneration(s.multiaccountsDB, s.logger),
|
||||
imagesPath: handleImage(s.db, s.logger),
|
||||
ipfsPath: handleIPFS(s.downloader, s.logger),
|
||||
LinkPreviewThumbnailPath: handleLinkPreviewThumbnail(s.db, s.logger),
|
||||
StatusLinkPreviewThumbnailPath: handleStatusLinkPreviewThumbnail(s.db, s.logger),
|
||||
communityTokenImagesPath: handleCommunityTokenImages(s.db, s.logger),
|
||||
walletCommunityImagesPath: handleWalletCommunityImages(s.walletDB, s.logger),
|
||||
walletCollectionImagesPath: handleWalletCollectionImages(s.walletDB, s.logger),
|
||||
walletCollectibleImagesPath: handleWalletCollectibleImages(s.walletDB, s.logger),
|
||||
})
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeImageServerURL() string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = basePath + "/"
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeImageURL(id string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = imagesPath
|
||||
u.RawQuery = url.Values{"messageId": {id}}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeLinkPreviewThumbnailURL(msgID string, previewURL string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = LinkPreviewThumbnailPath
|
||||
u.RawQuery = url.Values{"message-id": {msgID}, "url": {previewURL}}.Encode()
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeStatusLinkPreviewThumbnailURL(msgID string, previewURL string, imageID common.MediaServerImageID) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = StatusLinkPreviewThumbnailPath
|
||||
u.RawQuery = url.Values{"message-id": {msgID}, "url": {previewURL}, "image-id": {string(imageID)}}.Encode()
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeDiscordAuthorAvatarURL(authorID string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = discordAuthorsPath
|
||||
u.RawQuery = url.Values{"authorId": {authorID}}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeDiscordAttachmentURL(messageID string, id string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = discordAttachmentsPath
|
||||
u.RawQuery = url.Values{"messageId": {messageID}, "attachmentId": {id}}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeAudioURL(id string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = audioPath
|
||||
u.RawQuery = url.Values{"messageId": {id}}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeStickerURL(stickerHash string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = ipfsPath
|
||||
u.RawQuery = url.Values{"hash": {stickerHash}}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeQRURL(qurul string,
|
||||
allowProfileImage string,
|
||||
level string,
|
||||
size string,
|
||||
keyUID string,
|
||||
imageName string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = generateQRCode
|
||||
u.RawQuery = url.Values{"url": {qurul},
|
||||
"level": {level},
|
||||
"allowProfileImage": {allowProfileImage},
|
||||
"size": {size},
|
||||
"keyUid": {keyUID},
|
||||
"imageName": {imageName}}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeContactImageURL(publicKey string, imageType string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = contactImagesPath
|
||||
u.RawQuery = url.Values{"publicKey": {publicKey}, "imageName": {imageType}}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeCommunityTokenImagesURL(communityID string, chainID uint64, symbol string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = communityTokenImagesPath
|
||||
u.RawQuery = url.Values{
|
||||
"communityID": {communityID},
|
||||
"chainID": {strconv.FormatUint(chainID, 10)},
|
||||
"symbol": {symbol},
|
||||
}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeWalletCommunityImagesURL(communityID string) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = walletCommunityImagesPath
|
||||
u.RawQuery = url.Values{
|
||||
"communityID": {communityID},
|
||||
}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeWalletCollectionImagesURL(contractID thirdparty.ContractID) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = walletCollectionImagesPath
|
||||
u.RawQuery = url.Values{
|
||||
"chainID": {contractID.ChainID.String()},
|
||||
"contractAddress": {contractID.Address.Hex()},
|
||||
}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
|
||||
func (s *MediaServer) MakeWalletCollectibleImagesURL(collectibleID thirdparty.CollectibleUniqueID) string {
|
||||
u := s.MakeBaseURL()
|
||||
u.Path = walletCollectibleImagesPath
|
||||
u.RawQuery = url.Values{
|
||||
"chainID": {collectibleID.ContractID.ChainID.String()},
|
||||
"contractAddress": {collectibleID.ContractID.Address.Hex()},
|
||||
"tokenID": {collectibleID.TokenID.String()},
|
||||
}.Encode()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
94
vendor/github.com/status-im/status-go/server/timeout.go
generated
vendored
Normal file
94
vendor/github.com/status-im/status-go/server/timeout.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// timeoutManager represents a discrete encapsulation of timeout functionality.
|
||||
// this struct expose 3 functions:
|
||||
// - SetTimeout
|
||||
// - StartTimeout
|
||||
// - StopTimeout
|
||||
type timeoutManager struct {
|
||||
// timeout number of milliseconds the timeout operation will run before executing the `terminate` func()
|
||||
// 0 represents an inactive timeout
|
||||
timeout uint
|
||||
|
||||
// exitQueue handles the cancel signal channels that circumvent timeout operations and prevent the
|
||||
// execution of any `terminate` func()
|
||||
exitQueue *exitQueueManager
|
||||
}
|
||||
|
||||
// newTimeoutManager returns a fully qualified and initialised timeoutManager
|
||||
func newTimeoutManager() *timeoutManager {
|
||||
return &timeoutManager{
|
||||
exitQueue: &exitQueueManager{queue: []chan struct{}{}},
|
||||
}
|
||||
}
|
||||
|
||||
// SetTimeout sets the value of the timeoutManager.timeout
|
||||
func (t *timeoutManager) SetTimeout(milliseconds uint) {
|
||||
t.timeout = milliseconds
|
||||
}
|
||||
|
||||
// StartTimeout starts a timeout operation based on the set timeoutManager.timeout value
|
||||
// the given terminate func() will be executed once the timeout duration has passed
|
||||
func (t *timeoutManager) StartTimeout(terminate func()) {
|
||||
if t.timeout == 0 {
|
||||
return
|
||||
}
|
||||
t.StopTimeout()
|
||||
|
||||
exit := make(chan struct{}, 1)
|
||||
t.exitQueue.add(exit)
|
||||
go t.run(terminate, exit)
|
||||
}
|
||||
|
||||
// StopTimeout terminates a timeout operation and exits gracefully
|
||||
func (t *timeoutManager) StopTimeout() {
|
||||
if t.timeout == 0 {
|
||||
return
|
||||
}
|
||||
t.exitQueue.empty()
|
||||
}
|
||||
|
||||
// run inits the main timeout run function that awaits for the exit command to be triggered or for the
|
||||
// timeout duration to elapse and trigger the parameter terminate function.
|
||||
func (t *timeoutManager) run(terminate func(), exit chan struct{}) {
|
||||
select {
|
||||
case <-exit:
|
||||
return
|
||||
case <-time.After(time.Duration(t.timeout) * time.Millisecond):
|
||||
terminate()
|
||||
// TODO fire signal to let UI know
|
||||
// https://github.com/status-im/status-go/issues/3305
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// exitQueueManager
|
||||
type exitQueueManager struct {
|
||||
queue []chan struct{}
|
||||
queueLock sync.Mutex
|
||||
}
|
||||
|
||||
// add handles new exit channels adding them to the exit queue
|
||||
func (e *exitQueueManager) add(exit chan struct{}) {
|
||||
e.queueLock.Lock()
|
||||
defer e.queueLock.Unlock()
|
||||
|
||||
e.queue = append(e.queue, exit)
|
||||
}
|
||||
|
||||
// empty sends a signal to every exit channel in the queue and then resets the queue
|
||||
func (e *exitQueueManager) empty() {
|
||||
e.queueLock.Lock()
|
||||
defer e.queueLock.Unlock()
|
||||
|
||||
for i := range e.queue {
|
||||
e.queue[i] <- struct{}{}
|
||||
}
|
||||
|
||||
e.queue = []chan struct{}{}
|
||||
}
|
||||
Reference in New Issue
Block a user