stealing
commit
cbf886fb7e
|
|
@ -0,0 +1,11 @@
|
|||
lz4
|
||||
rclone
|
||||
rcloner
|
||||
Go
|
||||
cloudly
|
||||
dockfile
|
||||
compile.sh
|
||||
*.swp
|
||||
*.swo
|
||||
*pycache*
|
||||
enc_conf
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"local/s2sa/s2sa/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
server := server.New("")
|
||||
if err := server.Routes(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := server.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"local/s2sa/s2sa/server/router"
|
||||
"local/s2sa/s2sa/services"
|
||||
"local/s2sa/s2sa/storage"
|
||||
)
|
||||
|
||||
func New(path string) *Server {
|
||||
var db storage.DB
|
||||
db = storage.NewMap()
|
||||
if len(path) > 0 {
|
||||
var err error
|
||||
db, err = storage.NewBolt(path)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
authdb := storage.NewMap()
|
||||
s := &Server{
|
||||
db: services.New(db),
|
||||
authdb: services.New(authdb),
|
||||
router: router.New(),
|
||||
addr: ":18341",
|
||||
}
|
||||
if err := s.authdb.Register(serverNS); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServerNew(t *testing.T) {
|
||||
New("")
|
||||
New(os.DevNull)
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"local/s2sa/s2sa/server/router"
|
||||
"local/s2sa/s2sa/token"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const clientsNS = "clients"
|
||||
const accessorsNS = "accessors"
|
||||
const wildcard = "{}"
|
||||
const serverNS = "server"
|
||||
|
||||
func (s *Server) Routes() error {
|
||||
appendWildcards := func(s string, cnt int) string {
|
||||
s = strings.Trim(s, "/")
|
||||
return path.Join(s, strings.Repeat("/"+wildcard, cnt))
|
||||
}
|
||||
paths := []struct {
|
||||
base string
|
||||
wildcards int
|
||||
method http.HandlerFunc
|
||||
}{
|
||||
{
|
||||
base: "admin/register",
|
||||
wildcards: 1,
|
||||
method: s.adminRegister,
|
||||
},
|
||||
{
|
||||
base: "register",
|
||||
wildcards: 1,
|
||||
method: s.authenticate(s.registerClient),
|
||||
},
|
||||
{
|
||||
base: "generate",
|
||||
wildcards: 2,
|
||||
method: s.authenticate(s.generateToken),
|
||||
},
|
||||
{
|
||||
base: "retrieve",
|
||||
wildcards: 3,
|
||||
method: s.authenticate(s.retrieveToken),
|
||||
},
|
||||
{
|
||||
base: "revoke",
|
||||
wildcards: 2,
|
||||
method: s.authenticate(s.revokeToken),
|
||||
},
|
||||
{
|
||||
base: "lookup",
|
||||
wildcards: 2,
|
||||
method: s.authenticate(s.lookupToken),
|
||||
},
|
||||
{
|
||||
base: "policies",
|
||||
wildcards: 0,
|
||||
method: s.authenticate(s.getPolicies),
|
||||
},
|
||||
}
|
||||
for _, path := range paths {
|
||||
if err := s.Add(appendWildcards(path.base, path.wildcards), path.method); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) authenticate(foo http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
recipient, accessorToken, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
accessor := strings.Split(accessorToken, ":")[0]
|
||||
tokenValue := strings.Split(accessorToken, ":")[1]
|
||||
|
||||
token, err := s.authdb.Get(recipient, accessor)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if token.Token != tokenValue {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if token.To != recipient {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
foo(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) adminRegister(w http.ResponseWriter, r *http.Request) {
|
||||
var name string
|
||||
if err := router.Params(r, &name); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := s.authdb.New(serverNS, name)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
respondWithToken(token, w, r)
|
||||
}
|
||||
|
||||
func (s *Server) registerClient(w http.ResponseWriter, r *http.Request) {
|
||||
var name string
|
||||
if err := router.Params(r, &name); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.db.Register(name); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) generateToken(w http.ResponseWriter, r *http.Request) {
|
||||
var name, to string
|
||||
if err := router.Params(r, &name, &to); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := s.db.New(name, to)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
respondWithToken(token, w, r)
|
||||
}
|
||||
|
||||
func (s *Server) retrieveToken(w http.ResponseWriter, r *http.Request) {
|
||||
var creator, recipient, accessor string
|
||||
if err := router.Params(r, &creator, &recipient, &accessor); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := s.db.Get(recipient, accessor)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
respondWithToken(token, w, r)
|
||||
}
|
||||
|
||||
func respondWithToken(token token.Basic, w http.ResponseWriter, r *http.Request) {
|
||||
if err := json.NewEncoder(w).Encode(token); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) revokeToken(w http.ResponseWriter, r *http.Request) {
|
||||
var name, accessor string
|
||||
if err := router.Params(r, &name, &accessor); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.db.Revoke(name, accessor); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) lookupToken(w http.ResponseWriter, r *http.Request) {
|
||||
var creator, recipient string
|
||||
if err := router.Params(r, &creator, &recipient); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
token, err := s.db.Lookup(creator, recipient)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
respondWithToken(token, w, r)
|
||||
}
|
||||
|
||||
func (s *Server) getPolicies(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
|
@ -0,0 +1,437 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type badRouter struct {
|
||||
accept []string
|
||||
}
|
||||
|
||||
func (br *badRouter) Add(p string, h http.HandlerFunc) error {
|
||||
for i := range br.accept {
|
||||
if br.accept[i] == p {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("rejected path")
|
||||
}
|
||||
|
||||
func (br *badRouter) ServeHTTP(http.ResponseWriter, *http.Request) {}
|
||||
|
||||
func TestServerRoutesBadRouter(t *testing.T) {
|
||||
server, _, _ := mockServer()
|
||||
br := badRouter{
|
||||
accept: make([]string, 0),
|
||||
}
|
||||
server.router = &br
|
||||
|
||||
toAdd := []string{
|
||||
"/nil",
|
||||
"/admin/register/{}",
|
||||
"/register/{}",
|
||||
"/generate/{}/{}",
|
||||
"/retrieve/{}/{}",
|
||||
"/revoke/{}/{}",
|
||||
"/lookup/{}/{}",
|
||||
"/policies",
|
||||
}
|
||||
|
||||
for _, path := range toAdd {
|
||||
br.accept = append(br.accept, path)
|
||||
if err := server.Routes(); err == nil {
|
||||
t.Errorf("can add non-allowed routes")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerRoutes(t *testing.T) {
|
||||
server, _, _ := mockServer()
|
||||
if err := server.db.Register("a"); err != nil {
|
||||
t.Fatalf("cannot register: %v", err)
|
||||
}
|
||||
token, err := server.db.New("a", "b")
|
||||
if err != nil {
|
||||
t.Fatalf("cannot new: %v", err)
|
||||
}
|
||||
|
||||
paths := []string{
|
||||
"retrieve/a/b/" + token.Accessor,
|
||||
"revoke/a/" + token.Accessor,
|
||||
"lookup/a/b",
|
||||
"policies",
|
||||
"admin/register/a",
|
||||
"register/a",
|
||||
"generate/a/b",
|
||||
}
|
||||
|
||||
for _, p := range paths {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", p, nil)
|
||||
server.ServeHTTP(w, r)
|
||||
if w.Code == 404 {
|
||||
t.Errorf("not found for %v", p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerAdminRegister(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
status int
|
||||
}{
|
||||
{
|
||||
name: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
status: 200,
|
||||
},
|
||||
}
|
||||
|
||||
path := "admin/register"
|
||||
server, _, _ := mockServer()
|
||||
|
||||
for i, c := range cases {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", path, nil)
|
||||
r = addParam(r, "name", c.name)
|
||||
server.ServeHTTP(w, r)
|
||||
if w.Code != c.status {
|
||||
t.Errorf("[%d] wrong code for %s: got %d, expected %d", i, path, w.Code, c.status)
|
||||
}
|
||||
body, _ := ioutil.ReadAll(w.Body)
|
||||
if len(body) < 1 {
|
||||
t.Errorf("[%d] empty body in admin/register response: %q", i, body)
|
||||
}
|
||||
t.Logf("[%d] admin/register body: %q", i, body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerRegister(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
status int
|
||||
}{
|
||||
{
|
||||
name: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
status: 200,
|
||||
},
|
||||
}
|
||||
|
||||
path := "register"
|
||||
server, _, _ := mockServer()
|
||||
|
||||
for i, c := range cases {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", path, nil)
|
||||
r = addParam(r, "name", c.name)
|
||||
auth, err := server.authdb.New(serverNS, c.name)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot authdb new: %v", err)
|
||||
}
|
||||
r.SetBasicAuth(c.name, auth.Accessor+":"+auth.Token)
|
||||
server.ServeHTTP(w, r)
|
||||
if w.Code != c.status {
|
||||
t.Errorf("%d: wrong code for %s: got %d, expected %d", i, path, w.Code, c.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerGenerate(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
to string
|
||||
status int
|
||||
}{
|
||||
{
|
||||
name: "",
|
||||
to: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
to: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: "",
|
||||
to: "to",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
to: "to",
|
||||
status: 200,
|
||||
},
|
||||
}
|
||||
|
||||
path := "generate"
|
||||
server, _, _ := mockServer()
|
||||
|
||||
for i, c := range cases {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", path, nil)
|
||||
r = addParam(r, "name", c.name)
|
||||
r = addParam(r, "to", c.to)
|
||||
auth, err := server.authdb.New(serverNS, c.name)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot authdb new: %v", err)
|
||||
}
|
||||
r.SetBasicAuth(c.name, auth.Accessor+":"+auth.Token)
|
||||
server.ServeHTTP(w, r)
|
||||
if w.Code != c.status {
|
||||
t.Errorf("%d: wrong code for %s: got %d, expected %d", i, path, w.Code, c.status)
|
||||
}
|
||||
var result struct {
|
||||
Token string `json:"token"`
|
||||
Acc string `json:"accessor"`
|
||||
TTL int `json:"TTL"`
|
||||
To string `json:"to"`
|
||||
}
|
||||
if err := json.NewDecoder(w.Body).Decode(&result); c.status == 200 && err != nil {
|
||||
t.Errorf("invalid body: %v", err)
|
||||
} else if c.status == 200 {
|
||||
if result.To != c.to {
|
||||
t.Errorf("wrong `to` in response: got %v, want %v", result.To, c.to)
|
||||
}
|
||||
if len(result.Token) == 0 {
|
||||
t.Errorf("empty `token` in response")
|
||||
}
|
||||
if len(result.Acc) == 0 {
|
||||
t.Errorf("empty `accessor` in response")
|
||||
}
|
||||
if result.TTL < 100 {
|
||||
t.Errorf("short TTL in response")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerRetrieve(t *testing.T) {
|
||||
server, defaultName, defaultAccessor := mockServer()
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
acc string
|
||||
status int
|
||||
}{
|
||||
{
|
||||
name: "",
|
||||
acc: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: defaultName,
|
||||
acc: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: "",
|
||||
acc: defaultAccessor,
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: defaultName,
|
||||
acc: defaultAccessor,
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
name: "fake",
|
||||
acc: "fake",
|
||||
status: 400,
|
||||
},
|
||||
}
|
||||
|
||||
path := "retrieve"
|
||||
for i, c := range cases {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", path, nil)
|
||||
r = addParam(r, "name", c.name)
|
||||
r = addParam(r, "to", "to")
|
||||
r = addParam(r, "accessor", c.acc)
|
||||
auth, err := server.authdb.New(serverNS, c.name)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot authdb new: %v", err)
|
||||
}
|
||||
r.SetBasicAuth(c.name, auth.Accessor+":"+auth.Token)
|
||||
server.ServeHTTP(w, r)
|
||||
if w.Code != c.status {
|
||||
//t.Errorf("%d: wrong code for %s with %v: got %d, expected %d", i, path, c, w.Code, c.status)
|
||||
t.Fatalf("%d: wrong code for %s with %v: got %d, expected %d", i, path, c, w.Code, c.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerRevoke(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
status int
|
||||
}{
|
||||
{
|
||||
name: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
status: 200,
|
||||
},
|
||||
}
|
||||
|
||||
path := "register"
|
||||
server, _, _ := mockServer()
|
||||
|
||||
for i, c := range cases {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", path, nil)
|
||||
r = addParam(r, "name", c.name)
|
||||
auth, err := server.authdb.New(serverNS, c.name)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot authdb new: %v", err)
|
||||
}
|
||||
r.SetBasicAuth(c.name, auth.Accessor+":"+auth.Token)
|
||||
server.ServeHTTP(w, r)
|
||||
if w.Code != c.status {
|
||||
t.Errorf("%d: wrong code for %s: got %d, expected %d", i, path, w.Code, c.status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestServerLookup(t *testing.T) {
|
||||
from := "from"
|
||||
to := "to"
|
||||
cases := []struct {
|
||||
from string
|
||||
to string
|
||||
status int
|
||||
}{
|
||||
{
|
||||
from: "",
|
||||
to: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
from: "",
|
||||
to: to,
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
from: from,
|
||||
to: "",
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
from: from,
|
||||
to: to,
|
||||
status: 200,
|
||||
},
|
||||
}
|
||||
|
||||
path := "lookup"
|
||||
server, _, _ := mockServer()
|
||||
server.db.Register(from)
|
||||
generated, _ := server.db.New(from, to)
|
||||
|
||||
for i, c := range cases {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", path, nil)
|
||||
r = addParam(r, "from", c.from)
|
||||
r = addParam(r, "to", c.to)
|
||||
auth, err := server.authdb.New(serverNS, c.from)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot authdb new: %v", err)
|
||||
}
|
||||
r.SetBasicAuth(c.from, auth.Accessor+":"+auth.Token)
|
||||
server.ServeHTTP(w, r)
|
||||
if w.Code != c.status {
|
||||
t.Errorf("%d: wrong code for %s: got %d, expected %d", i, path, w.Code, c.status)
|
||||
}
|
||||
if w.Code != http.StatusOK {
|
||||
continue
|
||||
}
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: cannot read body: %v", i, err)
|
||||
}
|
||||
if !bytes.Contains(b, []byte(generated.Accessor)) {
|
||||
t.Errorf("%d: response didn't contain accessor: got %s, want %s", i, b, generated.Accessor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func echoHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(r.URL.Path))
|
||||
}
|
||||
|
||||
func addParam(r *http.Request, key, value string) *http.Request {
|
||||
r.URL.Path += "/" + value
|
||||
r.Header.Set(key, value)
|
||||
return r
|
||||
}
|
||||
|
||||
func TestServerAuthenticate(t *testing.T) {
|
||||
server, _, _ := mockServer()
|
||||
|
||||
name := "name"
|
||||
server.authdb.Register(serverNS)
|
||||
token, err := server.authdb.New(serverNS, name)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot authdb new: %v", err)
|
||||
}
|
||||
|
||||
nilHandle := func(http.ResponseWriter, *http.Request) {}
|
||||
authFunc := server.authenticate(nilHandle)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
token string
|
||||
accessor string
|
||||
code int
|
||||
}{
|
||||
{
|
||||
name: "bad",
|
||||
token: token.Token,
|
||||
accessor: token.Accessor,
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
{
|
||||
name: name,
|
||||
token: token.Token,
|
||||
accessor: "bad",
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
{
|
||||
name: name,
|
||||
token: "bad",
|
||||
accessor: token.Accessor,
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
{
|
||||
name: name,
|
||||
token: token.Token,
|
||||
accessor: token.Accessor,
|
||||
code: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", "/any", nil)
|
||||
r.SetBasicAuth(c.name, c.accessor+":"+c.token)
|
||||
authFunc(w, r)
|
||||
if w.Code != c.code {
|
||||
t.Errorf("[case %d] failed auth: got %v, wanted %v", i, w.Code, c.code)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"local/s2sa/s2sa/logg"
|
||||
"local/s2sa/s2sa/server/router"
|
||||
"local/s2sa/s2sa/token"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Router interface {
|
||||
Add(string, http.HandlerFunc) error
|
||||
ServeHTTP(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
type TokenDatabase interface {
|
||||
Register(string) error
|
||||
New(string, string) (token.Basic, error)
|
||||
Get(string, string) (token.Basic, error)
|
||||
Revoke(string, string) error
|
||||
Lookup(string, string) (token.Basic, error)
|
||||
}
|
||||
|
||||
type Messenger interface {
|
||||
Produce(string, interface{}) error
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
router Router
|
||||
db TokenDatabase
|
||||
authdb TokenDatabase
|
||||
messenger Messenger
|
||||
addr string
|
||||
}
|
||||
|
||||
func (s *Server) Add(path string, handler http.HandlerFunc) error {
|
||||
logg.Logf("Adding path %v...\n", path)
|
||||
path = strings.Replace(path, wildcard, router.Wildcard, -1)
|
||||
return s.router.Add(path, handler)
|
||||
}
|
||||
|
||||
func (s *Server) Run() error {
|
||||
logg.Logf("Listening on %v...\n", s.addr)
|
||||
return http.ListenAndServe(s.addr, s)
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Printf("REQ: %s\n", r.URL.Path)
|
||||
s.router.ServeHTTP(w, r)
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"local/s2sa/s2sa/logg"
|
||||
"local/s2sa/s2sa/server/router"
|
||||
"local/s2sa/s2sa/services"
|
||||
"local/s2sa/s2sa/storage"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestServerStart(t *testing.T) {
|
||||
server, _, _ := mockServer()
|
||||
|
||||
checked := false
|
||||
if err := server.Add("/hello/world", func(_ http.ResponseWriter, _ *http.Request) {
|
||||
checked = true
|
||||
}); err != nil {
|
||||
t.Fatalf("cannot add route: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := server.Run(); err != nil {
|
||||
t.Fatalf("err running server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if resp, err := http.Get("http://localhost" + server.addr + "/hello/world"); err != nil {
|
||||
t.Errorf("failed to get: %v", err)
|
||||
} else if resp.StatusCode != 200 {
|
||||
t.Errorf("wrong status: %v", resp.StatusCode)
|
||||
} else if !checked {
|
||||
t.Errorf("didnt hit handler")
|
||||
}
|
||||
}
|
||||
|
||||
func mockServer() (*Server, string, string) {
|
||||
f, _ := os.Open(os.DevNull)
|
||||
logg.ConfigFile(f)
|
||||
portServer := httptest.NewServer(nil)
|
||||
port := strings.Split(portServer.URL, ":")[2]
|
||||
portServer.Close()
|
||||
s := &Server{
|
||||
router: router.New(),
|
||||
db: services.New(storage.NewMap()),
|
||||
authdb: services.New(storage.NewMap()),
|
||||
addr: ":" + port,
|
||||
}
|
||||
s.authdb.Register(serverNS)
|
||||
if err := s.Routes(); err != nil {
|
||||
panic(fmt.Sprintf("cannot initiate server routes; %v", err))
|
||||
}
|
||||
|
||||
defaultName := "name"
|
||||
if err := s.db.Register(defaultName); err != nil {
|
||||
panic(fmt.Sprintf("cannot register: %v", err))
|
||||
}
|
||||
token, err := s.db.New("name", "to")
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("cannot generate: %v", err))
|
||||
}
|
||||
defaultAccessor := token.Accessor
|
||||
return s, defaultName, defaultAccessor
|
||||
}
|
||||
|
||||
func TestServerAdd(t *testing.T) {
|
||||
server, _, _ := mockServer()
|
||||
path := "/hello/world"
|
||||
if err := server.Add(path, echoHTTP); err != nil {
|
||||
t.Fatalf("cannot add path: %v", err)
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest("GET", path, nil)
|
||||
server.ServeHTTP(w, r)
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot read body: %v", err)
|
||||
}
|
||||
if string(b) != path {
|
||||
t.Errorf("cannot hit endpoint: %s", b)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package storage
|
||||
|
||||
import "local/rproxy3/storage/packable"
|
||||
|
||||
type DB interface {
|
||||
Get(string, string, packable.Packable) error
|
||||
Set(string, string, packable.Packable) error
|
||||
Close() error
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"local/rproxy3/storage/packable"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDB(t *testing.T) {
|
||||
dbPath := "./fake_db_path"
|
||||
defer os.Remove(dbPath)
|
||||
|
||||
cases := []func() DB{
|
||||
func() DB {
|
||||
return DB(NewMap())
|
||||
},
|
||||
}
|
||||
|
||||
raw := "hello world"
|
||||
for _, c := range cases {
|
||||
os.Remove(dbPath)
|
||||
|
||||
s := packable.NewString(raw)
|
||||
db := c()
|
||||
if err := db.Set("ns", "key", s); err != nil {
|
||||
t.Errorf("cannot save: %v", err)
|
||||
}
|
||||
|
||||
r := packable.NewString("")
|
||||
if err := db.Get("ns", "key", r); err != nil {
|
||||
t.Errorf("cannot load: %v", err)
|
||||
}
|
||||
|
||||
if s.String() != r.String() {
|
||||
t.Errorf("set/get values not equal: %v vs %v", s, r)
|
||||
}
|
||||
|
||||
if s.String() != raw {
|
||||
t.Errorf("set/get values not equal to raw: %v vs %v", s, raw)
|
||||
}
|
||||
|
||||
if err := db.Close(); err != nil {
|
||||
t.Errorf("cannot close bolt: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"local/rproxy3/storage/packable"
|
||||
)
|
||||
|
||||
type Map map[string]map[string][]byte
|
||||
|
||||
func NewMap() Map {
|
||||
m := make(map[string]map[string][]byte)
|
||||
n := Map(m)
|
||||
return n
|
||||
}
|
||||
|
||||
func (m Map) String() string {
|
||||
s := ""
|
||||
for k, v := range m {
|
||||
if k == "clients" {
|
||||
if s != "" {
|
||||
s += ",\n"
|
||||
}
|
||||
s += fmt.Sprintf("[%s]:[%v]", k, v)
|
||||
} else {
|
||||
for k1, _ := range v {
|
||||
if s != "" {
|
||||
s += ",\n"
|
||||
}
|
||||
str := packable.NewString("")
|
||||
m.Get(k, k1, str)
|
||||
s += fmt.Sprintf("[%s:%s]:[%v]", k, k1, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (m Map) Close() error {
|
||||
m = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Map) Get(ns, key string, value packable.Packable) error {
|
||||
if _, ok := m[ns]; !ok {
|
||||
m[ns] = make(map[string][]byte)
|
||||
}
|
||||
if _, ok := m[ns][key]; !ok {
|
||||
return errors.New("not found")
|
||||
}
|
||||
return value.Decode(m[ns][key])
|
||||
}
|
||||
|
||||
func (m Map) Set(ns, key string, value packable.Packable) error {
|
||||
if _, ok := m[ns]; !ok {
|
||||
m[ns] = make(map[string][]byte)
|
||||
}
|
||||
b, err := value.Encode()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m[ns][key] = b
|
||||
return nil
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package packable
|
||||
|
||||
type Packable interface {
|
||||
Encode() ([]byte, error)
|
||||
Decode([]byte) error
|
||||
}
|
||||
|
||||
type String string
|
||||
|
||||
func (s *String) String() string {
|
||||
return string(*s)
|
||||
}
|
||||
|
||||
func (s *String) Encode() ([]byte, error) {
|
||||
return []byte(*s), nil
|
||||
}
|
||||
|
||||
func (s *String) Decode(b []byte) error {
|
||||
*s = String(string(b))
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewString(s string) *String {
|
||||
w := String(s)
|
||||
return &w
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package packable
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestPackableString(t *testing.T) {
|
||||
raw := "hello"
|
||||
s := NewString(raw)
|
||||
if s.String() != raw {
|
||||
t.Errorf("cannot convert string to String: %v vs %v", s, raw)
|
||||
}
|
||||
|
||||
packed, err := s.Encode()
|
||||
if err != nil {
|
||||
t.Errorf("cannot encode String: %v", err)
|
||||
}
|
||||
|
||||
x := NewString("")
|
||||
if err := x.Decode(packed); err != nil {
|
||||
t.Errorf("cannot decode string: %v", err)
|
||||
} else if x.String() != raw {
|
||||
t.Errorf("wrong decoded string: %v vs %v", x, raw)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"comment": "",
|
||||
"ignore": "test",
|
||||
"package": [],
|
||||
"rootPath": "local/rproxy3"
|
||||
}
|
||||
Loading…
Reference in New Issue