Showing
8 changed files
with
237 additions
and
0 deletions
source/server/.gitignore
0 → 100644
1 | + | ||
2 | +# Created by https://www.toptal.com/developers/gitignore/api/go,vscode | ||
3 | +# Edit at https://www.toptal.com/developers/gitignore?templates=go,vscode | ||
4 | + | ||
5 | +### Go ### | ||
6 | +# Binaries for programs and plugins | ||
7 | +*.exe | ||
8 | +*.exe~ | ||
9 | +*.dll | ||
10 | +*.so | ||
11 | +*.dylib | ||
12 | + | ||
13 | +# Test binary, built with `go test -c` | ||
14 | +*.test | ||
15 | + | ||
16 | +# Output of the go coverage tool, specifically when used with LiteIDE | ||
17 | +*.out | ||
18 | + | ||
19 | +# Dependency directories (remove the comment below to include it) | ||
20 | +# vendor/ | ||
21 | + | ||
22 | +### Go Patch ### | ||
23 | +/vendor/ | ||
24 | +/Godeps/ | ||
25 | + | ||
26 | +### vscode ### | ||
27 | +.vscode/* | ||
28 | +!.vscode/settings.json | ||
29 | +!.vscode/tasks.json | ||
30 | +!.vscode/launch.json | ||
31 | +!.vscode/extensions.json | ||
32 | +*.code-workspace | ||
33 | + | ||
34 | +# End of https://www.toptal.com/developers/gitignore/api/go,vscode | ||
35 | + | ||
36 | +__debug_bin | ||
37 | +config.json | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
source/server/app.go
0 → 100644
1 | +package main | ||
2 | + | ||
3 | +import ( | ||
4 | + "fmt" | ||
5 | + "net/http" | ||
6 | + | ||
7 | + "github.com/gorilla/mux" | ||
8 | + | ||
9 | + _ "github.com/go-sql-driver/mysql" | ||
10 | + "github.com/jmoiron/sqlx" | ||
11 | +) | ||
12 | + | ||
13 | +type App struct { | ||
14 | + Config Config | ||
15 | + db *sqlx.DB | ||
16 | + router *mux.Router | ||
17 | +} | ||
18 | + | ||
19 | +func NewApp(config Config) *App { | ||
20 | + app := new(App) | ||
21 | + app.Config = config | ||
22 | + | ||
23 | + dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s", config.Database.User, config.Database.Password, config.Database.Host, config.Database.Name) | ||
24 | + app.db = sqlx.MustOpen("mysql", dsn) | ||
25 | + | ||
26 | + app.router = mux.NewRouter() | ||
27 | + app.router.HandleFunc("/users", app.PostUsers).Methods("POST") | ||
28 | + app.router.HandleFunc("/users/tokens", app.PostTokens).Methods("POST") | ||
29 | + | ||
30 | + return app | ||
31 | +} | ||
32 | + | ||
33 | +func (app *App) Serve() { | ||
34 | + http.ListenAndServe(fmt.Sprintf(":%d", app.Config.Port), app.router) | ||
35 | +} |
source/server/config.go
0 → 100644
1 | +package main | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "io/ioutil" | ||
6 | +) | ||
7 | + | ||
8 | +type Config struct { | ||
9 | + Port int `json:"port"` | ||
10 | + Database struct { | ||
11 | + Host string `json:"host"` | ||
12 | + Name string `json:"name"` | ||
13 | + User string `json:"user"` | ||
14 | + Password string `json:"password"` | ||
15 | + } `json:"database"` | ||
16 | + TokenSecret string `json:"token_secret"` | ||
17 | +} | ||
18 | + | ||
19 | +func LoadConfig(path string) (Config, error) { | ||
20 | + config := Config{} | ||
21 | + | ||
22 | + data, err := ioutil.ReadFile(path) | ||
23 | + if err == nil { | ||
24 | + err = json.Unmarshal(data, &config) | ||
25 | + } | ||
26 | + | ||
27 | + return config, err | ||
28 | +} |
source/server/go.mod
0 → 100644
source/server/go.sum
0 → 100644
1 | +github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM= | ||
2 | +github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | ||
3 | +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||
4 | +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||
5 | +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= | ||
6 | +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= | ||
7 | +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= | ||
8 | +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= | ||
9 | +github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= | ||
10 | +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= | ||
11 | +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= | ||
12 | +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | ||
13 | +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
14 | +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= | ||
15 | +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||
16 | +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
17 | +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
18 | +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= | ||
19 | +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
20 | +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
source/server/main.go
0 → 100644
source/server/user.go
0 → 100644
1 | +package main | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "net/http" | ||
6 | + "time" | ||
7 | + | ||
8 | + "github.com/dgrijalva/jwt-go" | ||
9 | + "github.com/go-sql-driver/mysql" | ||
10 | + "golang.org/x/crypto/sha3" | ||
11 | +) | ||
12 | + | ||
13 | +type User struct { | ||
14 | + No uint64 `json:"no"` | ||
15 | + ID string `json:"id"` | ||
16 | + Name string `json:"name"` | ||
17 | + CreatedAt time.Time `json:"created_at"` | ||
18 | + ExpiredAt time.Time `json:"expired_at"` | ||
19 | +} | ||
20 | + | ||
21 | +func (app *App) PostUsers(w http.ResponseWriter, r *http.Request) { | ||
22 | + body := make(map[string]interface{}) | ||
23 | + err := json.NewDecoder(r.Body).Decode(&body) | ||
24 | + if err != nil { | ||
25 | + WriteJson(w, http.StatusBadRequest, map[string]interface{}{"msg": "Failed to parse request json"}) | ||
26 | + return | ||
27 | + } | ||
28 | + | ||
29 | + hash := sha3.Sum256([]byte(body["password"].(string))) | ||
30 | + | ||
31 | + res, err := app.db.Exec("INSERT INTO users (`id`, `password`, `name`) VALUES (?, ?, ?)", body["id"], hash[:], body["name"]) | ||
32 | + if err != nil { | ||
33 | + if merr, ok := err.(*mysql.MySQLError); ok { | ||
34 | + if merr.Number == 1062 { | ||
35 | + WriteJson(w, http.StatusConflict, map[string]interface{}{"msg": "Already registered"}) | ||
36 | + return | ||
37 | + } | ||
38 | + } | ||
39 | + | ||
40 | + WriteJson(w, http.StatusInternalServerError, map[string]interface{}{"msg": "Failed to register"}) | ||
41 | + return | ||
42 | + } | ||
43 | + | ||
44 | + no, _ := res.LastInsertId() | ||
45 | + WriteJson(w, http.StatusOK, map[string]interface{}{"user_no": no}) | ||
46 | +} | ||
47 | + | ||
48 | +func (app *App) PostTokens(w http.ResponseWriter, r *http.Request) { | ||
49 | + body := make(map[string]interface{}) | ||
50 | + err := json.NewDecoder(r.Body).Decode(&body) | ||
51 | + if err != nil { | ||
52 | + WriteJson(w, http.StatusBadRequest, map[string]interface{}{"msg": "Failed to parse request json"}) | ||
53 | + return | ||
54 | + } | ||
55 | + | ||
56 | + hash := sha3.Sum256([]byte(body["password"].(string))) | ||
57 | + rows, err := app.db.Query("SELECT `no` FROM users WHERE `id`=? AND `password`=?", body["id"], hash[:]) | ||
58 | + if err != nil { | ||
59 | + WriteJson(w, http.StatusInternalServerError, map[string]interface{}{"msg": "Failed to register"}) | ||
60 | + return | ||
61 | + } | ||
62 | + | ||
63 | + if !rows.Next() { | ||
64 | + WriteJson(w, http.StatusUnauthorized, map[string]interface{}{"msg": "Login failed"}) | ||
65 | + return | ||
66 | + } | ||
67 | + | ||
68 | + no := uint64(0) | ||
69 | + rows.Scan(&no) | ||
70 | + | ||
71 | + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"no": no}) | ||
72 | + auth, err := token.SignedString([]byte(app.Config.TokenSecret)) | ||
73 | + if err != nil { | ||
74 | + WriteJson(w, http.StatusInternalServerError, map[string]interface{}{"msg": "Login failed"}) | ||
75 | + return | ||
76 | + } | ||
77 | + | ||
78 | + WriteJson(w, http.StatusOK, map[string]interface{}{"token": auth}) | ||
79 | +} |
source/server/util.go
0 → 100644
-
Please register or login to post a comment