mirror of
https://github.com/kataras/iris.git
synced 2025-01-23 18:51:03 +01:00
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:
parent
9dbb300d9b
commit
2576b3da34
|
@ -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.
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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"})
|
||||||
//
|
//
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
2
go.mod
|
@ -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
|
||||||
|
|
|
@ -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/)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user