github.com/geph-official/geph2@v0.22.6-0.20210211030601-f527cb59b0df/cmd/geph-binder/tickets.go (about)

     1  package main
     2  
     3  import (
     4  	"crypto/x509"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"log"
     8  	"net/http"
     9  	"runtime"
    10  	"sort"
    11  	"strings"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/cryptoballot/rsablind"
    16  	"github.com/geph-official/geph2/libs/bdclient"
    17  	"github.com/patrickmn/go-cache"
    18  )
    19  
    20  func handleGetTicketKey(w http.ResponseWriter, r *http.Request) {
    21  	countUserAgent(r)
    22  	// check type
    23  	key, err := getTicketIdentity(r.FormValue("tier"))
    24  	if err != nil {
    25  		w.WriteHeader(http.StatusInternalServerError)
    26  		return
    27  	}
    28  	w.Write([]byte(base64.RawStdEncoding.EncodeToString(x509.MarshalPKCS1PublicKey(&key.PublicKey))))
    29  }
    30  
    31  func handleGetTier(w http.ResponseWriter, r *http.Request) {
    32  	countUserAgent(r)
    33  	// first authenticate
    34  	_, expiry, _, err := verifyUser(r.FormValue("user"), r.FormValue("pwd"))
    35  	if err != nil {
    36  		log.Println("cannot verify user:", err.Error())
    37  		w.WriteHeader(http.StatusInternalServerError)
    38  		return
    39  	}
    40  	if expiry.After(time.Now()) {
    41  		w.Write([]byte("paid"))
    42  	} else {
    43  		w.Write([]byte("free"))
    44  	}
    45  }
    46  
    47  var cpuSemaphore chan bool
    48  
    49  func init() {
    50  	cpuSemaphore = make(chan bool, runtime.GOMAXPROCS(0)*2)
    51  }
    52  
    53  var limiterCache sync.Map
    54  
    55  var goodIPCache = cache.New(time.Hour, time.Minute)
    56  
    57  func handleGetTicket(w http.ResponseWriter, r *http.Request) {
    58  	countUserAgent(r)
    59  	// first authenticate
    60  	uid, expiry, paytx, err := verifyUser(r.FormValue("user"), r.FormValue("pwd"))
    61  	if err != nil {
    62  		log.Println("cannot verify user:", err.Error())
    63  		w.WriteHeader(http.StatusInternalServerError)
    64  		return
    65  	}
    66  	if uid < 0 {
    67  		log.Println("cannot log in user:", r.FormValue("user"))
    68  		w.WriteHeader(http.StatusForbidden)
    69  		return
    70  	}
    71  	// ticketLimiter, _ := limiterCache.LoadOrStore(uid, rate.NewLimiter(rate.Every(time.Minute*4), 100))
    72  	// if !ticketLimiter.(*rate.Limiter).Allow() {
    73  	// 	log.Println("*** VIOLATED LIMIT ", r.FormValue("user"))
    74  	// 	time.Sleep(time.Second * 10)
    75  	// 	w.WriteHeader(http.StatusTooManyRequests)
    76  	// 	return
    77  	// }
    78  	log.Println("verified", r.FormValue("user"))
    79  	//log.Println("get-ticket: verified user", r.FormValue("user"), "as expiry", expiry)
    80  	var tier string
    81  	if expiry.After(time.Now()) {
    82  		tier = "paid"
    83  	} else {
    84  		tier = "free"
    85  	}
    86  	blinded, err := base64.RawStdEncoding.DecodeString(r.FormValue("blinded"))
    87  	if err != nil {
    88  		w.WriteHeader(http.StatusBadRequest)
    89  		return
    90  	}
    91  	//log.Println("get-ticket: user", r.FormValue("user"), "sent us blinded of length", len(blinded))
    92  	// get the key
    93  	key, err := getTicketIdentity(tier)
    94  	if err != nil {
    95  		w.WriteHeader(http.StatusInternalServerError)
    96  		return
    97  	}
    98  	// issue the ticket. TODO rate limit this
    99  	ticket, err := rsablind.BlindSign(key, blinded)
   100  	if err != nil {
   101  		panic(err)
   102  	}
   103  	var toWrite bdclient.TicketResp
   104  	toWrite.Tier = tier
   105  	toWrite.Ticket = ticket
   106  	toWrite.PaidExpiry = expiry
   107  	if paytx != nil {
   108  		for k, v := range paytx {
   109  			toWrite.Transactions = append(toWrite.Transactions, bdclient.PaymentTx{
   110  				Amount: v,
   111  				Date:   k,
   112  			})
   113  		}
   114  		sort.Slice(toWrite.Transactions, func(i, j int) bool {
   115  			return toWrite.Transactions[i].Date.After(toWrite.Transactions[j].Date)
   116  		})
   117  	}
   118  	b, err := json.Marshal(toWrite)
   119  	if err != nil {
   120  		panic(err)
   121  	}
   122  	w.Write([]byte(b))
   123  	id := strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0]
   124  	goodIPCache.SetDefault(id, uid)
   125  }
   126  
   127  func handleRedeemTicket(w http.ResponseWriter, r *http.Request) {
   128  	countUserAgent(r)
   129  	// check type
   130  	if tier := r.FormValue("tier"); tier != "free" && tier != "paid" {
   131  		log.Println("bad tier:", tier)
   132  		w.WriteHeader(http.StatusBadRequest)
   133  		return
   134  	}
   135  	// obtain key
   136  	key, err := getTicketIdentity(r.FormValue("tier"))
   137  	if err != nil {
   138  		w.WriteHeader(http.StatusInternalServerError)
   139  		return
   140  	}
   141  	// obtain values
   142  	ubmsg, err := base64.RawStdEncoding.DecodeString(r.FormValue("ubmsg"))
   143  	if err != nil {
   144  		w.WriteHeader(http.StatusBadRequest)
   145  		return
   146  	}
   147  	ubsig, err := base64.RawStdEncoding.DecodeString(r.FormValue("ubsig"))
   148  	if err != nil {
   149  		w.WriteHeader(http.StatusBadRequest)
   150  		return
   151  	}
   152  	// verify
   153  	if err := rsablind.VerifyBlindSignature(&key.PublicKey, ubmsg, ubsig); err != nil {
   154  		w.WriteHeader(http.StatusForbidden)
   155  		return
   156  	}
   157  	return
   158  }