add support for iris-specific form of generating connection IDs as requested at: https://github.com/kataras/neffos/issues/1#issuecomment-508689819

Former-commit-id: 0994b63373ebe2b5383a28f042aa2133061cbd18
This commit is contained in:
Gerasimos (Makis) Maropoulos 2019-07-05 16:22:20 +03:00
parent 9dbb300d9b
commit 2576b3da34
9 changed files with 65 additions and 39 deletions

View File

@ -8,7 +8,8 @@ import (
) )
var ( var (
// Change that to your owns, usally you have an ECDSA private key // Change that to your own key.
// Usually you have an ECDSA private key
// per identify, let's say a user, stored in a database // per identify, let's say a user, stored in a database
// or somewhere else and you use its public key // or somewhere else and you use its public key
// to sign a user's payload and when this client // to sign a user's payload and when this client
@ -17,11 +18,9 @@ var (
// with the user's public key. // with the user's public key.
// //
// Use the crypto.MustGenerateKey to generate a random key // Use the crypto.MustGenerateKey to generate a random key
// or import // or
// the "github.com/kataras/iris/crypto/sign" // crypto.ParsePrivateKey to convert data or local file to an *ecdsa.PrivateKey.
// and use its // and `crypto.ParsePublicKey` if you only have access to the public one.
// sign.ParsePrivateKey/ParsePublicKey(theKey []byte)
// to convert data or local file to an *ecdsa.PrivateKey.
testPrivateKey = crypto.MustGenerateKey() testPrivateKey = crypto.MustGenerateKey()
testPublicKey = &testPrivateKey.PublicKey testPublicKey = &testPrivateKey.PublicKey
) )
@ -34,7 +33,7 @@ type testPayloadStructure struct {
// The Iris crypto package offers // The Iris crypto package offers
// authentication (with optional encryption in top of) and verification // authentication (with optional encryption in top of) and verification
// of raw []byte data with `crypto.Marshal/Unmarshal` functions // of raw []byte data with `crypto.Marshal/Unmarshal` functions
// and JSON payloads with `crypto.SignJSON/VerifyJSON functions. // and JSON payloads with `crypto.SignJSON/VerifyJSON` functions.
// //
// Let's use the `SignJSON` and `VerifyJSON` here as an example, // Let's use the `SignJSON` and `VerifyJSON` here as an example,
// as this is the most common scenario for a web application. // as this is the most common scenario for a web application.

View File

@ -28,7 +28,7 @@ import (
"github.com/fatih/structs" "github.com/fatih/structs"
"github.com/iris-contrib/blackfriday" "github.com/iris-contrib/blackfriday"
formbinder "github.com/iris-contrib/formBinder" formbinder "github.com/iris-contrib/formBinder"
"github.com/json-iterator/go" jsoniter "github.com/json-iterator/go"
"github.com/microcosm-cc/bluemonday" "github.com/microcosm-cc/bluemonday"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
@ -826,7 +826,7 @@ type Context interface {
// //
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
SetCookieKV(name, value string, options ...CookieOption) SetCookieKV(name, value string, options ...CookieOption)
// GetCookie returns cookie's value by it's name // GetCookie returns cookie's value by its name
// returns empty string if nothing was found. // returns empty string if nothing was found.
// //
// If you want more than the value then: // If you want more than the value then:
@ -834,12 +834,12 @@ type Context interface {
// //
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
GetCookie(name string, options ...CookieOption) string GetCookie(name string, options ...CookieOption) string
// RemoveCookie deletes a cookie by it's name and path = "/". // RemoveCookie deletes a cookie by its name and path = "/".
// Tip: change the cookie's path to the current one by: RemoveCookie("name", iris.CookieCleanPath) // Tip: change the cookie's path to the current one by: RemoveCookie("name", iris.CookieCleanPath)
// //
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
RemoveCookie(name string, options ...CookieOption) RemoveCookie(name string, options ...CookieOption)
// VisitAllCookies takes a visitor which loops // VisitAllCookies accepts a visitor function which is called
// on each (request's) cookies' name and value. // on each (request's) cookies' name and value.
VisitAllCookies(visitor func(name string, value string)) VisitAllCookies(visitor func(name string, value string))
@ -3233,7 +3233,7 @@ func CookieHTTPOnly(httpOnly bool) CookieOption {
type ( type (
// CookieEncoder should encode the cookie value. // CookieEncoder should encode the cookie value.
// Should accept as first argument the cookie name // Should accept the cookie's name as its first argument
// and as second argument the cookie value ptr. // and as second argument the cookie value ptr.
// Should return an encoded value or an empty one if encode operation failed. // Should return an encoded value or an empty one if encode operation failed.
// Should return an error if encode operation failed. // Should return an error if encode operation failed.
@ -3245,7 +3245,7 @@ type (
// See `CookieDecoder` too. // See `CookieDecoder` too.
CookieEncoder func(cookieName string, value interface{}) (string, error) CookieEncoder func(cookieName string, value interface{}) (string, error)
// CookieDecoder should decode the cookie value. // CookieDecoder should decode the cookie value.
// Should accept as first argument the cookie name, // Should accept the cookie's name as its first argument,
// as second argument the encoded cookie value and as third argument the decoded value ptr. // as second argument the encoded cookie value and as third argument the decoded value ptr.
// Should return a decoded value or an empty one if decode operation failed. // Should return a decoded value or an empty one if decode operation failed.
// Should return an error if decode operation failed. // Should return an error if decode operation failed.
@ -3329,7 +3329,7 @@ func (ctx *context) SetCookieKV(name, value string, options ...CookieOption) {
ctx.SetCookie(c, options...) ctx.SetCookie(c, options...)
} }
// GetCookie returns cookie's value by it's name // GetCookie returns cookie's value by its name
// returns empty string if nothing was found. // returns empty string if nothing was found.
// //
// If you want more than the value then: // If you want more than the value then:
@ -3350,13 +3350,13 @@ func (ctx *context) GetCookie(name string, options ...CookieOption) string {
return value return value
} }
// SetCookieKVExpiration is 2 hours by-default // SetCookieKVExpiration is 365 days by-default
// you can change it or simple, use the SetCookie for more control. // you can change it or simple, use the SetCookie for more control.
// //
// See `SetCookieKVExpiration` and `CookieExpires` for more. // See `SetCookieKVExpiration` and `CookieExpires` for more.
var SetCookieKVExpiration = time.Duration(120) * time.Minute var SetCookieKVExpiration = time.Duration(8760) * time.Hour
// RemoveCookie deletes a cookie by it's name and path = "/". // RemoveCookie deletes a cookie by its name and path = "/".
// Tip: change the cookie's path to the current one by: RemoveCookie("name", iris.CookieCleanPath) // Tip: change the cookie's path to the current one by: RemoveCookie("name", iris.CookieCleanPath)
// //
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic // Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
@ -3375,7 +3375,7 @@ func (ctx *context) RemoveCookie(name string, options ...CookieOption) {
ctx.request.Header.Set("Cookie", "") ctx.request.Header.Set("Cookie", "")
} }
// VisitAllCookies takes a visitor which loops // VisitAllCookies takes a visitor function which is called
// on each (request's) cookies' name and value. // on each (request's) cookies' name and value.
func (ctx *context) VisitAllCookies(visitor func(name string, value string)) { func (ctx *context) VisitAllCookies(visitor func(name string, value string)) {
for _, cookie := range ctx.request.Cookies() { for _, cookie := range ctx.request.Cookies() {

View File

@ -397,7 +397,7 @@ func (api *APIBuilder) HandleMany(methodOrMulti string, relativePathorMulti stri
// second parameter : the system or the embedded directory that needs to be served // second parameter : the system or the embedded directory that needs to be served
// third parameter : not required, the directory options, set fields is optional. // third parameter : not required, the directory options, set fields is optional.
// //
// for more options look router.FileServer. // Alternatively, to get just the handler for that look the FileServer function instead.
// //
// api.HandleDir("/static", "./assets", DirOptions {ShowList: true, Gzip: true, IndexName: "index.html"}) // api.HandleDir("/static", "./assets", DirOptions {ShowList: true, Gzip: true, IndexName: "index.html"})
// //

View File

@ -9,9 +9,13 @@ import (
) )
var ( var (
// MustGenerateKey generates an ecdsa public and private key pair. // MustGenerateKey generates an ecdsa private and public key pair.
// It panics if any error occurred. // It panics if any error occurred.
MustGenerateKey = sign.MustGenerateKey MustGenerateKey = sign.MustGenerateKey
// ParsePrivateKey accepts a pem x509-encoded private key and decodes to *ecdsa.PrivateKey.
ParsePrivateKey = sign.ParsePrivateKey
// ParsePublicKey accepts a pem x509-encoded public key and decodes to *ecdsa.PrivateKey.
ParsePublicKey = sign.ParsePublicKey
// MustGenerateAESKey generates an aes key. // MustGenerateAESKey generates an aes key.
// It panics if any error occurred. // It panics if any error occurred.
@ -79,9 +83,9 @@ func Decrypt(aesKey, additionalData []byte) Decryption {
// Returns non-nil error if any error occurred. // Returns non-nil error if any error occurred.
// //
// Usage: // Usage:
// data, _ := ioutil.ReadAll(r.Body) // data, _ := ioutil.ReadAll(ctx.Request().Body)
// signedData, err := crypto.Marshal(testPrivateKey, data, nil) // signedData, err := crypto.Marshal(testPrivateKey, data, nil)
// w.Write(signedData) // ctx.Write(signedData)
// Or if data should be encrypted: // Or if data should be encrypted:
// signedEncryptedData, err := crypto.Marshal(testPrivateKey, data, crypto.Encrypt(aesKey, nil)) // signedEncryptedData, err := crypto.Marshal(testPrivateKey, data, crypto.Encrypt(aesKey, nil))
func Marshal(privateKey *ecdsa.PrivateKey, data []byte, encrypt Encryption) ([]byte, error) { func Marshal(privateKey *ecdsa.PrivateKey, data []byte, encrypt Encryption) ([]byte, error) {

View File

@ -53,11 +53,11 @@ func SignJSON(privateKey *ecdsa.PrivateKey, r io.Reader) (Ticket, error) {
// VerifyJSON verifies the incoming JSON request, // VerifyJSON verifies the incoming JSON request,
// by reading the "r" which should decodes to a `Ticket`. // by reading the "r" which should decodes to a `Ticket`.
// The `Ticket` is verified against the given "publicKey", the `Ticket#Signature` and // The `Ticket` is verified against the given "publicKey", the `Ticket#Signature` and
// `Ticket#Payload` data (original request's payload data which was signed by `SignPayload`). // `Ticket#Payload` data (original request's payload data which was signed by `SignJSON`).
// //
// Returns true wether the verification succeed or not. // Returns true whether the verification succeed or not.
// The "toPayloadPtr" should be a pointer to a value of the same payload structure the client signed on. // The "toPayloadPtr" should be a pointer to a value of the same payload structure the client signed on.
// If and only if the verification succeed the payload value is filled from the `Ticket#Payload` raw data. // If and only if the verification succeed the payload value is filled from the `Ticket.Payload` raw data.
// //
// Check for both output arguments in order to: // Check for both output arguments in order to:
// 1. verification (true/false and error) and // 1. verification (true/false and error) and

View File

@ -20,7 +20,7 @@ import (
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
) )
// MustGenerateKey generates a public and private key pair. // MustGenerateKey generates a private and public key pair.
// It panics if any error occurred. // It panics if any error occurred.
func MustGenerateKey() *ecdsa.PrivateKey { func MustGenerateKey() *ecdsa.PrivateKey {
privateKey, err := GenerateKey() privateKey, err := GenerateKey()
@ -31,7 +31,7 @@ func MustGenerateKey() *ecdsa.PrivateKey {
return privateKey return privateKey
} }
// GenerateKey generates a public and private key pair. // GenerateKey generates a private and public key pair.
func GenerateKey() (*ecdsa.PrivateKey, error) { func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
} }

2
go.mod
View File

@ -15,7 +15,7 @@ require (
github.com/iris-contrib/go.uuid v2.0.0+incompatible github.com/iris-contrib/go.uuid v2.0.0+incompatible
github.com/json-iterator/go v1.1.6 // vendor removed. github.com/json-iterator/go v1.1.6 // vendor removed.
github.com/kataras/golog v0.0.0-20180321173939-03be10146386 github.com/kataras/golog v0.0.0-20180321173939-03be10146386
github.com/kataras/neffos v0.0.2 github.com/kataras/neffos v0.0.3
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d // indirect github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d // indirect
github.com/microcosm-cc/bluemonday v1.0.2 github.com/microcosm-cc/bluemonday v1.0.2
github.com/ryanuber/columnize v2.1.0+incompatible github.com/ryanuber/columnize v2.1.0+incompatible

View File

@ -3,7 +3,7 @@
Iris supports 6 template engines out-of-the-box, developers can still use any external golang template engine, Iris supports 6 template engines out-of-the-box, developers can still use any external golang template engine,
as `context/context#ResponseWriter()` is an `io.Writer`. as `context/context#ResponseWriter()` is an `io.Writer`.
All of these five template engines have common features with common API, All of these six template engines have common features with common API,
like Layout, Template Funcs, Party-specific layout, partial rendering and more. like Layout, Template Funcs, Party-specific layout, partial rendering and more.
- The standard html, its template parser is the [golang.org/pkg/html/template/](https://golang.org/pkg/html/template/) - The standard html, its template parser is the [golang.org/pkg/html/template/](https://golang.org/pkg/html/template/)

View File

@ -28,8 +28,10 @@ var (
// See examples for more. // See examples for more.
New = neffos.New New = neffos.New
// DefaultIDGenerator returns a universal unique identifier for a new connection. // DefaultIDGenerator returns a universal unique identifier for a new connection.
// It's the default `IDGenerator` for `Server`. // It's the default `IDGenerator` if missing.
DefaultIDGenerator = neffos.DefaultIDGenerator DefaultIDGenerator = func(ctx context.Context) string {
return neffos.DefaultIDGenerator(ctx.ResponseWriter(), ctx.Request())
}
// GorillaDialer is a `Dialer` type for the gorilla/websocket subprotocol implementation. // GorillaDialer is a `Dialer` type for the gorilla/websocket subprotocol implementation.
// Should be used on `Dial` to create a new client/client-side connection. // Should be used on `Dial` to create a new client/client-side connection.
@ -113,16 +115,37 @@ func SetDefaultUnmarshaler(fn func(data []byte, v interface{}) error) {
neffos.DefaultUnmarshaler = fn neffos.DefaultUnmarshaler = fn
} }
// IDGenerator is an iris-specific IDGenerator for new connections.
type IDGenerator func(context.Context) string
// Handler returns an Iris handler to be served in a route of an Iris application. // Handler returns an Iris handler to be served in a route of an Iris application.
func Handler(s *neffos.Server) context.Handler { // Accepts the neffos websocket server as its first input argument
// and optionally an Iris-specific `IDGenerator` as its second one.
func Handler(s *neffos.Server, IDGenerator ...IDGenerator) context.Handler {
idGen := DefaultIDGenerator
if len(IDGenerator) > 0 {
idGen = IDGenerator[0]
}
return func(ctx context.Context) { return func(ctx context.Context) {
s.Upgrade(ctx.ResponseWriter(), ctx.Request(), func(socket neffos.Socket) neffos.Socket { if ctx.IsStopped() {
return
}
Upgrade(ctx, idGen(ctx), s)
}
}
// Upgrade upgrades the request and returns a new websocket Conn.
// Use `Handler` for higher-level implementation instead.
func Upgrade(ctx context.Context, customID string, s *neffos.Server) *neffos.Conn {
conn, _ := s.Upgrade(ctx.ResponseWriter(), ctx.Request(), func(socket neffos.Socket) neffos.Socket {
return &socketWrapper{ return &socketWrapper{
Socket: socket, Socket: socket,
ctx: ctx, ctx: ctx,
} }
}) }, customID)
}
return conn
} }
type socketWrapper struct { type socketWrapper struct {