mirror of https://github.com/cbeuw/Cloak
Implement admin control through a tunneled RESTful API
parent
98a772b6ee
commit
2ce6f380d1
@ -0,0 +1,159 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
description: |
|
||||
This is the API of Cloak server
|
||||
version: 1.0.0
|
||||
title: Cloak Server
|
||||
contact:
|
||||
email: cbeuw.andy@gmail.com
|
||||
license:
|
||||
name: GPLv3
|
||||
url: https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||
# host: petstore.swagger.io
|
||||
# basePath: /v2
|
||||
tags:
|
||||
- name: admin
|
||||
description: Endpoints used by the host administrators
|
||||
- name: users
|
||||
description: Operations related to user controls by admin
|
||||
# schemes:
|
||||
# - http
|
||||
paths:
|
||||
/admin/users:
|
||||
get:
|
||||
tags:
|
||||
- admin
|
||||
- users
|
||||
summary: Show all users
|
||||
description: Returns an array of all UserInfo
|
||||
operationId: listAllUsers
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
200:
|
||||
description: successful operation
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/UserInfo'
|
||||
500:
|
||||
description: internal error
|
||||
/admin/users/{UID}:
|
||||
get:
|
||||
tags:
|
||||
- admin
|
||||
- users
|
||||
summary: Show userinfo by UID
|
||||
description: Returns a UserInfo object
|
||||
operationId: getUserInfo
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- name: UID
|
||||
in: path
|
||||
description: UID of the user
|
||||
required: true
|
||||
type: string
|
||||
format: byte
|
||||
responses:
|
||||
200:
|
||||
description: successful operation
|
||||
schema:
|
||||
$ref: '#/definitions/UserInfo'
|
||||
400:
|
||||
description: bad request
|
||||
404:
|
||||
description: User not found
|
||||
500:
|
||||
description: internal error
|
||||
post:
|
||||
tags:
|
||||
- admin
|
||||
- users
|
||||
summary: Updates the userinfo of the specified user, if the user does not exist, then a new user is created
|
||||
operationId: writeUserInfo
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- name: UID
|
||||
in: path
|
||||
description: UID of the user
|
||||
required: true
|
||||
type: string
|
||||
format: byte
|
||||
- name: UserInfo
|
||||
in: body
|
||||
description: New userinfo
|
||||
required: true
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/UserInfo'
|
||||
responses:
|
||||
201:
|
||||
description: successful operation
|
||||
400:
|
||||
description: bad request
|
||||
500:
|
||||
description: internal error
|
||||
delete:
|
||||
tags:
|
||||
- admin
|
||||
- users
|
||||
summary: Deletes a user
|
||||
operationId: deleteUser
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- name: UID
|
||||
in: path
|
||||
description: UID of the user to be deleted
|
||||
required: true
|
||||
type: string
|
||||
format: byte
|
||||
responses:
|
||||
200:
|
||||
description: successful operation
|
||||
400:
|
||||
description: bad request
|
||||
404:
|
||||
description: User not found
|
||||
500:
|
||||
description: internal error
|
||||
|
||||
definitions:
|
||||
UserInfo:
|
||||
type: object
|
||||
properties:
|
||||
UID:
|
||||
type: string
|
||||
format: byte
|
||||
SessionsCap:
|
||||
type: integer
|
||||
format: int32
|
||||
UpRate:
|
||||
type: integer
|
||||
format: int64
|
||||
DownRate:
|
||||
type: integer
|
||||
format: int64
|
||||
UpCredit:
|
||||
type: integer
|
||||
format: int64
|
||||
DownCredit:
|
||||
type: integer
|
||||
format: int64
|
||||
ExpiryTime:
|
||||
type: integer
|
||||
format: int64
|
||||
externalDocs:
|
||||
description: Find out more about Swagger
|
||||
url: http://swagger.io
|
||||
# Added by API Auto Mocking Plugin
|
||||
host: virtserver.swaggerhub.com
|
||||
basePath: /cbeuw/ck-server/1.0.0
|
||||
schemes:
|
||||
- https
|
||||
- http
|
@ -0,0 +1,165 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"github.com/boltdb/bolt"
|
||||
"net/http"
|
||||
|
||||
gmux "github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type UserInfo struct {
|
||||
UID []byte
|
||||
SessionsCap int
|
||||
UpRate int64
|
||||
DownRate int64
|
||||
UpCredit int64
|
||||
DownCredit int64
|
||||
ExpiryTime int64
|
||||
}
|
||||
|
||||
func (manager *localManager) listAllUsersHlr(w http.ResponseWriter, r *http.Request) {
|
||||
var infos []UserInfo
|
||||
_ = manager.db.View(func(tx *bolt.Tx) error {
|
||||
err := tx.ForEach(func(UID []byte, bucket *bolt.Bucket) error {
|
||||
var uinfo UserInfo
|
||||
uinfo.UID = UID
|
||||
uinfo.SessionsCap = int(Uint32(bucket.Get([]byte("SessionsCap"))))
|
||||
uinfo.UpRate = int64(Uint64(bucket.Get([]byte("UpRate"))))
|
||||
uinfo.DownRate = int64(Uint64(bucket.Get([]byte("DownRate"))))
|
||||
uinfo.UpCredit = int64(Uint64(bucket.Get([]byte("UpCredit"))))
|
||||
uinfo.DownCredit = int64(Uint64(bucket.Get([]byte("DownCredit"))))
|
||||
uinfo.ExpiryTime = int64(Uint64(bucket.Get([]byte("ExpiryTime"))))
|
||||
infos = append(infos, uinfo)
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
})
|
||||
resp, err := json.Marshal(infos)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, _ = w.Write(resp)
|
||||
}
|
||||
|
||||
func (manager *localManager) getUserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
b64UID := gmux.Vars(r)["UID"]
|
||||
if b64UID == "" {
|
||||
http.Error(w, "UID cannot be empty", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
UID, err := base64.URLEncoding.DecodeString(b64UID)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var uinfo UserInfo
|
||||
err = manager.db.View(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket([]byte(UID))
|
||||
if bucket == nil {
|
||||
return ErrUserNotFound
|
||||
}
|
||||
uinfo.UID = UID
|
||||
uinfo.SessionsCap = int(Uint32(bucket.Get([]byte("SessionsCap"))))
|
||||
uinfo.UpRate = int64(Uint64(bucket.Get([]byte("UpRate"))))
|
||||
uinfo.DownRate = int64(Uint64(bucket.Get([]byte("DownRate"))))
|
||||
uinfo.UpCredit = int64(Uint64(bucket.Get([]byte("UpCredit"))))
|
||||
uinfo.DownCredit = int64(Uint64(bucket.Get([]byte("DownCredit"))))
|
||||
uinfo.ExpiryTime = int64(Uint64(bucket.Get([]byte("ExpiryTime"))))
|
||||
return nil
|
||||
})
|
||||
if err == ErrUserNotFound {
|
||||
http.Error(w, ErrUserNotFound.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
resp, err := json.Marshal(uinfo)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, _ = w.Write(resp)
|
||||
}
|
||||
|
||||
func (manager *localManager) writeUserInfo(w http.ResponseWriter, r *http.Request) {
|
||||
b64UID := gmux.Vars(r)["UID"]
|
||||
if b64UID == "" {
|
||||
http.Error(w, "UID cannot be empty", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
UID, err := base64.URLEncoding.DecodeString(b64UID)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
jsonUinfo := gmux.Vars(r)["UserInfo"]
|
||||
if jsonUinfo == "" {
|
||||
http.Error(w, "UserInfo cannot be empty", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var uinfo UserInfo
|
||||
err = json.Unmarshal([]byte(jsonUinfo), &uinfo)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !bytes.Equal(UID, uinfo.UID) {
|
||||
http.Error(w, "UID mismatch", http.StatusBadRequest)
|
||||
}
|
||||
|
||||
err = manager.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket, err := tx.CreateBucket(uinfo.UID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = bucket.Put([]byte("SessionsCap"), i32ToB(int32(uinfo.SessionsCap))); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = bucket.Put([]byte("UpRate"), i64ToB(uinfo.UpRate)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = bucket.Put([]byte("DownRate"), i64ToB(uinfo.DownRate)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = bucket.Put([]byte("UpCredit"), i64ToB(uinfo.UpCredit)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = bucket.Put([]byte("DownCredit"), i64ToB(uinfo.DownCredit)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = bucket.Put([]byte("ExpiryTime"), i64ToB(uinfo.ExpiryTime)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
|
||||
func (manager *localManager) deleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
b64UID := gmux.Vars(r)["UID"]
|
||||
if b64UID == "" {
|
||||
http.Error(w, "UID cannot be empty", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
UID, err := base64.URLEncoding.DecodeString(b64UID)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = manager.db.Update(func(tx *bolt.Tx) error {
|
||||
return tx.DeleteBucket(UID)
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
Loading…
Reference in New Issue