forked from NullableLabs/AlgoAuth
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
118 lines (106 loc) · 3.13 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package main
import (
"bytes"
"crypto/ed25519"
"encoding/base32"
"encoding/base64"
"errors"
"fmt"
//"github.com/algorand/go-algorand-sdk/crypto"
"github.com/algorand/go-algorand-sdk/encoding/msgpack"
"github.com/algorand/go-algorand-sdk/types"
"github.com/gin-contrib/gzip"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"log"
"net/http"
)
type transaction struct {
Payload string `json:"transaction" binding:"required"`
PubKey string `json:"pubkey" binding:"required"`
}
func GetPubKey(address string) (ed25519.PublicKey, error) {
checksumLenBytes := 4
decoded, err := base32.StdEncoding.WithPadding(base32.NoPadding).DecodeString(address)
if err != nil {
return nil, errors.New("could not decode algo address")
}
if len(decoded) != len(types.Address{})+checksumLenBytes {
return nil, errors.New("decoded algo address wrong length")
}
addressBytes := decoded[:len(types.Address{})]
return addressBytes, nil
}
func HomeRoutes(router *gin.Engine) {
router.GET("/", func(c *gin.Context) {
c.HTML(http.StatusOK, "pageHome.tmpl", gin.H{})
})
router.POST("/transaction", func(c *gin.Context) {
var transaction transaction
err := c.BindJSON(&transaction)
if err != nil {
c.AbortWithStatus(400)
return
}
// decoded the transaction, as the payload comes base64 encoded from the Typescript client
decodedTransaction, err := base64.StdEncoding.DecodeString(transaction.Payload)
if err != nil {
c.AbortWithStatus(400)
return
}
// decode the transaction with msgpack
var signedTxn types.SignedTxn
err = msgpack.Decode(decodedTransaction, &signedTxn)
if err != nil {
c.AbortWithStatus(400)
return
}
// parse the pubkey from the Algo address
pubkey, err := GetPubKey(transaction.PubKey)
if err != nil {
c.AbortWithStatus(400)
return
}
ret := rawVerifyTransaction(pubkey, signedTxn.Txn, signedTxn.Sig[:])
if ret {
fmt.Println("signature validated")
cookie := createCookie(pubkey)
http.SetCookie(c.Writer, &http.Cookie{Name: "session", Value: cookie, MaxAge: 500, HttpOnly: true})
c.JSON(200, `{"status": "validated"}`)
return
}
fmt.Println("signature not validated")
c.JSON(400, `{"status": "not validated"}`)
})
}
func rawVerifyTransaction(pubkey ed25519.PublicKey, transaction types.Transaction, sig []byte) bool {
note := transaction.Note
if bytes.Equal(note, []byte("website.URL & nonce")) { // implement your own note / nonce validation here
return false
}
domainSeparator := []byte("TX")
encodedTxn := msgpack.Encode(transaction)
msgParts := [][]byte{domainSeparator, encodedTxn}
toVerify := bytes.Join(msgParts, nil)
ret := ed25519.Verify(pubkey, toVerify, sig)
if ret {
return true
}
return false
}
func createCookie(pubkey ed25519.PublicKey) string {
// Implement your cookie logic here
return "abcd123"
}
func main() {
router := gin.Default()
router.Use(gin.Recovery())
router.Use(gzip.Gzip(gzip.DefaultCompression))
router.LoadHTMLGlob("src/templates/*.tmpl")
router.Use(static.Serve("/", static.LocalFile("src/www", false)))
HomeRoutes(router)
err := router.Run("0.0.0.0:9090")
if err != nil {
log.Panicln("could not start HTTP server")
}
}