kosyncsrv.git

ref: main

./kosyncsrv.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main

import (
	"flag"
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	_ "github.com/mattn/go-sqlite3"
)

type requestUser struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type requestHeader struct {
	AuthUser string `header:"x-auth-user"`
	AuthKey  string `header:"x-auth-key"`
}

type requestPosition struct {
	DocumentID string  `json:"document"`
	Percentage float64 `json:"percentage"`
	Progress   string  `json:"progress"`
	Device     string  `json:"device"`
	DeviceID   string  `json:"device_id"`
}

type replayPosition struct {
	DocumentID string
	Timestamp  int64
}

type requestDocid struct {
	DocumentID string `uri:"document" bingding:"required"`
}

func register(c *gin.Context) {
	var rUser requestUser
	if err := c.ShouldBindJSON(&rUser); err != nil {
		c.String(http.StatusBadRequest, "Bind Json error")
		return
	}

	if rUser.Username == "" || rUser.Password == "" {
		c.String(http.StatusBadRequest, "Invalid request")
		return
	} else if !addDBUser(rUser.Username, rUser.Password) {
		c.String(http.StatusConflict, "Username is already registered")
		return
	} else {
		c.JSON(http.StatusCreated, gin.H{
			"username": rUser.Username,
		})
		return
	}
}

func authorizeRequest(c *gin.Context) (ruser string) {
	var rHeader requestHeader
	if err := c.ShouldBindHeader(&rHeader); err != nil {
		c.String(http.StatusBadRequest, "Bind Header error")
	}
	if rHeader.AuthUser == "" || rHeader.AuthKey == "" {
		c.String(http.StatusUnauthorized, "Wrong header or Blank Value")
		return ruser
	}
	dUser, norows := getDBUser(rHeader.AuthUser)
	if norows {
		c.String(http.StatusForbidden, "Forbidden")
		return ruser
	} else if rHeader.AuthKey != dUser.Password {
		c.String(http.StatusUnauthorized, "Unauthorized")
		return ruser
	} else {
		return rHeader.AuthUser
	}
}

func authorize(c *gin.Context) {
	_ = authorizeRequest(c)
	c.JSON(200, gin.H{
		"authorized": "OK",
	})
}

func getProgress(c *gin.Context) {
	ruser := authorizeRequest(c)
	var rDocid requestDocid
	if err := c.ShouldBindUri(&rDocid); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"msg": err})
		return
	}
	position := getDBPosition(ruser, rDocid.DocumentID)
	c.JSON(http.StatusOK, position)
}

func updateProgress(c *gin.Context) {
	ruser := authorizeRequest(c)
	var rPosition requestPosition
	var reply replayPosition

	if err := c.ShouldBindJSON(&rPosition); err != nil {
		c.String(http.StatusBadRequest, "Bind Json error")
		return
	}
	updatetime := updateDBdocument(ruser, rPosition)
	reply.DocumentID = rPosition.DocumentID
	reply.Timestamp = updatetime
	c.JSON(http.StatusOK, reply)
}

func main() {
	dbfile := flag.String("d", "syncdata.db", "Sqlite3 DB file name")
	dbname = *dbfile
	srvhost := flag.String("t", "127.0.0.1", "Server host")
	srvport := flag.Int("p", 8080, "Server port")
	sslswitch := flag.Bool("ssl", false, "Start with https")
	sslc := flag.String("c", "", "SSL Certificate file")
	sslk := flag.String("k", "", "SSL Private key file")
	flag.Usage = func() {
		fmt.Println(`Usage: kosyncsrv [-h] [-t 127.0.0.1] [-p 8080] [-ssl -c "./cert.pem" -k "./cert.key"]`)
		flag.PrintDefaults()
	}
	flag.Parse()
	bindsrv := *srvhost + ":" + fmt.Sprint(*srvport)
	initDB()

	router := gin.Default()
	router.POST("/users/create", register)
	router.GET("/users/auth", authorize)
	router.GET("/syncs/progress/:document", getProgress)
	router.PUT("/syncs/progress", updateProgress)
	if *sslswitch {
		router.RunTLS(bindsrv, *sslc, *sslk)
	} else {
		router.Run(bindsrv)
	}
}