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 (
// 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
// or somewhere else and you use its public key
// to sign a user's payload and when this client
@ -17,11 +18,9 @@ var (
// with the user's public key.
//
// Use the crypto.MustGenerateKey to generate a random key
// or import
// the "github.com/kataras/iris/crypto/sign"
// and use its
// sign.ParsePrivateKey/ParsePublicKey(theKey []byte)
// to convert data or local file to an *ecdsa.PrivateKey.
// or
// crypto.ParsePrivateKey to convert data or local file to an *ecdsa.PrivateKey.
// and `crypto.ParsePublicKey` if you only have access to the public one.
testPrivateKey = crypto.MustGenerateKey()
testPublicKey = &testPrivateKey.PublicKey
)
@ -34,7 +33,7 @@ type testPayloadStructure struct {
// The Iris crypto package offers
// authentication (with optional encryption in top of) and verification
// 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,
// as this is the most common scenario for a web application.

View File

@ -28,7 +28,7 @@ import (
"github.com/fatih/structs"
"github.com/iris-contrib/blackfriday"
formbinder "github.com/iris-contrib/formBinder"
"github.com/json-iterator/go"
jsoniter "github.com/json-iterator/go"
"github.com/microcosm-cc/bluemonday"
"gopkg.in/yaml.v2"
)
@ -826,7 +826,7 @@ type Context interface {
//
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
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.
//
// 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
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)
//
// Example: https://github.com/kataras/iris/tree/master/_examples/cookies/basic
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.
VisitAllCookies(visitor func(name string, value string))
@ -3233,7 +3233,7 @@ func CookieHTTPOnly(httpOnly bool) CookieOption {
type (
// 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.
// Should return an encoded value or an empty one if encode operation failed.
// Should return an error if encode operation failed.
@ -3245,7 +3245,7 @@ type (
// See `CookieDecoder` too.
CookieEncoder func(cookieName string, value interface{}) (string, error)
// 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.
// Should return a decoded value or an empty one 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...)
}
// GetCookie returns cookie's value by it's name
// GetCookie returns cookie's value by its name
// returns empty string if nothing was found.
//
// If you want more than the value then:
@ -3350,13 +3350,13 @@ func (ctx *context) GetCookie(name string, options ...CookieOption) string {
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.
//
// 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)
//
// 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", "")
}
// VisitAllCookies takes a visitor which loops
// VisitAllCookies takes a visitor function which is called
// on each (request's) cookies' name and value.
func (ctx *context) VisitAllCookies(visitor func(name string, value string)) {
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
// 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"})
//

View File

@ -9,9 +9,13 @@ import (
)
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.
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.
// It panics if any error occurred.
@ -79,9 +83,9 @@ func Decrypt(aesKey, additionalData []byte) Decryption {
// Returns non-nil error if any error occurred.
//
// Usage:
// data, _ := ioutil.ReadAll(r.Body)
// data, _ := ioutil.ReadAll(ctx.Request().Body)
// signedData, err := crypto.Marshal(testPrivateKey, data, nil)
// w.Write(signedData)
// ctx.Write(signedData)
// Or if data should be encrypted:
// signedEncryptedData, err := crypto.Marshal(testPrivateKey, data, crypto.Encrypt(aesKey, nil))
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,
// by reading the "r" which should decodes to a `Ticket`.
// 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.
// 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:
// 1. verification (true/false and error) and

View File

@ -20,7 +20,7 @@ import (
"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.
func MustGenerateKey() *ecdsa.PrivateKey {
privateKey, err := GenerateKey()
@ -31,7 +31,7 @@ func MustGenerateKey() *ecdsa.PrivateKey {
return privateKey
}
// GenerateKey generates a public and private key pair.
// GenerateKey generates a private and public key pair.
func GenerateKey() (*ecdsa.PrivateKey, error) {
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/json-iterator/go v1.1.6 // vendor removed.
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/microcosm-cc/bluemonday v1.0.2
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,
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.
- 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.
New = neffos.New
// DefaultIDGenerator returns a universal unique identifier for a new connection.
// It's the default `IDGenerator` for `Server`.
DefaultIDGenerator = neffos.DefaultIDGenerator
// It's the default `IDGenerator` if missing.
DefaultIDGenerator = func(ctx context.Context) string {
return neffos.DefaultIDGenerator(ctx.ResponseWriter(), ctx.Request())
}
// GorillaDialer is a `Dialer` type for the gorilla/websocket subprotocol implementation.
// 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
}
// 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.
func Handler(s *neffos.Server) context.Handler {
return func(ctx context.Context) {
s.Upgrade(ctx.ResponseWriter(), ctx.Request(), func(socket neffos.Socket) neffos.Socket {
return &socketWrapper{
Socket: socket,
ctx: ctx,
}
})
// 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) {
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{
Socket: socket,
ctx: ctx,
}
}, customID)
return conn
}
type socketWrapper struct {