diff --git a/web/rpc.go b/web/rpc.go index 0fad8890..341ae77b 100644 --- a/web/rpc.go +++ b/web/rpc.go @@ -25,26 +25,38 @@ import ( type rpc struct{} +// -------------------------------------------------- +// Methods for authentication +// -------------------------------------------------- + func (r *rpc) Uniq(c *fibre.Context) (interface{}, error) { - return rand.String(128), nil + return rand.String(64), nil } func (r *rpc) Info(c *fibre.Context) (interface{}, error) { return c.Get("auth").(*cnf.Auth).Data, nil } -func (r *rpc) Auth(c *fibre.Context, auth string) (interface{}, error) { - return c.Get("auth").(*cnf.Auth).Data, checkBearer(c, auth, ignore) +func (r *rpc) Signup(c *fibre.Context, vars map[string]interface{}) (interface{}, error) { + return signupRpc(c, vars) } -func (r *rpc) Let(c *fibre.Context, key string, val interface{}) (interface{}, error) { - return c.Get("keep").(*data.Doc).Set(val, key) +func (r *rpc) Signin(c *fibre.Context, vars map[string]interface{}) (interface{}, error) { + return signinRpc(c, vars) } -func (r *rpc) Query(c *fibre.Context, sql string, vars map[string]interface{}) (interface{}, error) { - return db.Execute(c, sql, vars) +func (r *rpc) Invalidate(c *fibre.Context) (interface{}, error) { + return c.Get("auth").(*cnf.Auth).Reset().Data, nil } +func (r *rpc) Authenticate(c *fibre.Context, auth string) (interface{}, error) { + return c.Get("auth").(*cnf.Auth).Reset().Data, checkBearer(c, auth, ignore) +} + +// -------------------------------------------------- +// Methods for live queries +// -------------------------------------------------- + func (r *rpc) Kill(c *fibre.Context, query string) (interface{}, error) { return db.Execute(c, "KILL $query", map[string]interface{}{ "query": query, @@ -57,6 +69,18 @@ func (r *rpc) Live(c *fibre.Context, class string) (interface{}, error) { }) } +// -------------------------------------------------- +// Methods for static queries +// -------------------------------------------------- + +func (r *rpc) Let(c *fibre.Context, key string, val interface{}) (interface{}, error) { + return c.Get("keep").(*data.Doc).Set(val, key) +} + +func (r *rpc) Query(c *fibre.Context, sql string, vars map[string]interface{}) (interface{}, error) { + return db.Execute(c, sql, vars) +} + func (r *rpc) Select(c *fibre.Context, class string, thing interface{}) (interface{}, error) { switch thing := thing.(type) { case *fibre.RPCNull: diff --git a/web/signin.go b/web/signin.go index cc8025fc..52060542 100644 --- a/web/signin.go +++ b/web/signin.go @@ -34,6 +34,37 @@ func signin(c *fibre.Context) (err error) { c.Bind(&vars) + str, err := signinInternal(c, vars) + + switch err { + case nil: + return c.Send(200, str) + default: + return err + } + +} + +func signinRpc(c *fibre.Context, vars map[string]interface{}) (res interface{}, err error) { + + var str string + + str, err = signinInternal(c, vars) + if err != nil { + return nil, err + } + + err = checkBearer(c, str, ignore) + if err != nil { + return nil, err + } + + return str, nil + +} + +func signinInternal(c *fibre.Context, vars map[string]interface{}) (str string, err error) { + n, nok := vars[varKeyNs].(string) d, dok := vars[varKeyDb].(string) s, sok := vars[varKeySc].(string) @@ -58,7 +89,6 @@ func signin(c *fibre.Context) (err error) { var ok bool var txn kvs.TX - var str string var doc *sql.Thing var res []*db.Response var exp *sql.SubExpression @@ -67,7 +97,7 @@ func signin(c *fibre.Context) (err error) { // Start a new read transaction. if txn, err = db.Begin(false); err != nil { - return fibre.NewHTTPError(500) + return str, fibre.NewHTTPError(500) } // Ensure the transaction closes. @@ -82,14 +112,14 @@ func signin(c *fibre.Context) (err error) { if scp, err = mem.NewWithTX(txn).GetSC(n, d, s); err != nil { m := "Authentication scope does not exist" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // Check that the scope allows signin. if exp, ok = scp.Signin.(*sql.SubExpression); !ok { m := "Authentication scope does not allow signin" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // Process the scope signin statement. @@ -102,35 +132,35 @@ func signin(c *fibre.Context) (err error) { if res, err = db.Process(c, query, vars); err != nil { m := "Authentication scope signin was unsuccessful: Query failed" - return fibre.NewHTTPError(501).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(501).WithFields(f).WithMessage(m) } // If the response is not 1 record then return a 403 error. if len(res) != 1 { m := "Authentication scope signin was unsuccessful: Query failed" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // If the response has an error set then return a 403 error. if res[0].Status != "OK" { m := "Authentication scope signin was unsuccessful: " + res[0].Detail - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // If the response has no record set then return a 403 error. if len(res[0].Result) != 1 { m := "Authentication scope signin was unsuccessful: No record returned" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // If the query does not return an id field then return a 403 error. if doc, ok = data.Consume(res[0].Result[0]).Get("id").Data().(*sql.Thing); !ok { m := "Authentication scope signin was unsuccessful: No id field found" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // Create a new token signer with the default claims. @@ -152,10 +182,10 @@ func signin(c *fibre.Context) (err error) { if str, err = signr.SignedString(scp.Code); err != nil { m := "Problem with signing method: " + err.Error() - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } - return c.Send(200, str) + return str, err } @@ -181,13 +211,13 @@ func signin(c *fibre.Context) (err error) { if !uok || !pok { m := "Username or password is missing" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // Start a new read transaction. if usr, err = signinDB(n, d, u, p); err != nil { - return err + return str, err } // Create a new token signer with the default claims. @@ -207,10 +237,10 @@ func signin(c *fibre.Context) (err error) { if str, err = signr.SignedString(usr.Code); err != nil { m := "Problem with signing method: " + err.Error() - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } - return c.Send(200, str) + return str, err } @@ -236,11 +266,11 @@ func signin(c *fibre.Context) (err error) { if !uok || !pok { m := "Username or password is missing" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } if usr, err = signinNS(n, u, p); err != nil { - return err + return str, err } // Create a new token signer with the default claims. @@ -259,14 +289,14 @@ func signin(c *fibre.Context) (err error) { if str, err = signr.SignedString(usr.Code); err != nil { m := "Problem with signing method: " + err.Error() - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } - return c.Send(200, str) + return str, err } - return fibre.NewHTTPError(403) + return str, fibre.NewHTTPError(403) } diff --git a/web/signup.go b/web/signup.go index 91dfce94..e8a5f794 100644 --- a/web/signup.go +++ b/web/signup.go @@ -15,6 +15,8 @@ package web import ( + "time" + "github.com/abcum/fibre" "github.com/abcum/surreal/cnf" "github.com/abcum/surreal/db" @@ -22,6 +24,7 @@ import ( "github.com/abcum/surreal/mem" "github.com/abcum/surreal/sql" "github.com/abcum/surreal/util/data" + "github.com/dgrijalva/jwt-go" ) func signup(c *fibre.Context) (err error) { @@ -30,6 +33,37 @@ func signup(c *fibre.Context) (err error) { c.Bind(&vars) + str, err := signinInternal(c, vars) + + switch err { + case nil: + return c.Send(200, str) + default: + return err + } + +} + +func signupRpc(c *fibre.Context, vars map[string]interface{}) (res interface{}, err error) { + + var str string + + str, err = signupInternal(c, vars) + if err != nil { + return nil, err + } + + err = checkBearer(c, str, ignore) + if err != nil { + return nil, err + } + + return str, nil + +} + +func signupInternal(c *fibre.Context, vars map[string]interface{}) (str string, err error) { + n, nok := vars[varKeyNs].(string) d, dok := vars[varKeyDb].(string) s, sok := vars[varKeySc].(string) @@ -54,6 +88,7 @@ func signup(c *fibre.Context) (err error) { var ok bool var txn kvs.TX + var doc *sql.Thing var res []*db.Response var exp *sql.SubExpression var scp *sql.DefineScopeStatement @@ -61,7 +96,7 @@ func signup(c *fibre.Context) (err error) { // Start a new read transaction. if txn, err = db.Begin(false); err != nil { - return fibre.NewHTTPError(500) + return str, fibre.NewHTTPError(500) } // Ensure the transaction closes. @@ -76,14 +111,14 @@ func signup(c *fibre.Context) (err error) { if scp, err = mem.NewWithTX(txn).GetSC(n, d, s); err != nil { m := "Authentication scope does not exist" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // Check that the scope allows signup. if exp, ok = scp.Signup.(*sql.SubExpression); !ok { m := "Authentication scope does not allow signup" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // Process the scope signup statement. @@ -96,41 +131,63 @@ func signup(c *fibre.Context) (err error) { if res, err = db.Process(c, query, vars); err != nil { m := "Authentication scope signup was unsuccessful: Query failed" - return fibre.NewHTTPError(501).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(501).WithFields(f).WithMessage(m) } // If the response is not 1 record then return a 403 error. if len(res) != 1 { m := "Authentication scope signup was unsuccessful: Query failed" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // If the response has an error set then return a 403 error. if res[0].Status != "OK" { m := "Authentication scope signin was unsuccessful: " + res[0].Detail - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // If the response has no record set then return a 403 error. if len(res[0].Result) != 1 { m := "Authentication scope signup was unsuccessful: No record created" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } // If the query does not return an id field then return a 403 error. - if _, ok = data.Consume(res[0].Result[0]).Get("id").Data().(*sql.Thing); !ok { + if doc, ok = data.Consume(res[0].Result[0]).Get("id").Data().(*sql.Thing); !ok { m := "Authentication scope signup was unsuccessful: No id field found" - return fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) } - return c.Code(204) + // Create a new token signer with the default claims. + + signr := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{ + "NS": n, + "DB": d, + "SC": s, + "TK": "default", + "iss": "Surreal", + "iat": time.Now().Unix(), + "nbf": time.Now().Unix(), + "exp": time.Now().Add(scp.Time).Unix(), + "TB": doc.TB, + "ID": doc.ID, + }) + + // Try to create the final signed token as a string. + + if str, err = signr.SignedString(scp.Code); err != nil { + m := "Problem with signing method: " + err.Error() + return str, fibre.NewHTTPError(403).WithFields(f).WithMessage(m) + } + + return str, err } - return fibre.NewHTTPError(403) + return str, fibre.NewHTTPError(403) }