mirror of
https://github.com/kataras/iris.git
synced 2025-12-18 02:17:05 +00:00
replace ioutil with io package and other minor improvements
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -324,7 +323,7 @@ func BenchmarkAccessLogAfterPrint(b *testing.B) {
|
||||
}
|
||||
|
||||
func benchmarkAccessLogAfter(b *testing.B, withLogStruct, async bool) {
|
||||
ac := New(ioutil.Discard)
|
||||
ac := New(io.Discard)
|
||||
ac.Clock = TClock(time.Time{})
|
||||
ac.BytesReceived = false
|
||||
ac.BytesReceivedBody = false
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// Log represents the log data specifically for the accesslog middleware.
|
||||
//
|
||||
//easyjson:json
|
||||
type Log struct {
|
||||
// The AccessLog instance this Log was created of.
|
||||
|
||||
@@ -52,8 +52,9 @@ type ErrorHandler func(ctx *context.Context, err error)
|
||||
// The only required value is the Allow field.
|
||||
//
|
||||
// Usage:
|
||||
// opts := Options { ... }
|
||||
// auth := New(opts)
|
||||
//
|
||||
// opts := Options { ... }
|
||||
// auth := New(opts)
|
||||
type Options struct {
|
||||
// Realm directive, read http://tools.ietf.org/html/rfc2617#section-1.2 for details.
|
||||
// E.g. "Authorization Required".
|
||||
@@ -171,17 +172,18 @@ type BasicAuth struct {
|
||||
// The result should be used to wrap an existing handler or the HTTP application's root router.
|
||||
//
|
||||
// Example Code:
|
||||
// opts := basicauth.Options{
|
||||
// Realm: basicauth.DefaultRealm,
|
||||
// ErrorHandler: basicauth.DefaultErrorHandler,
|
||||
// MaxAge: 2 * time.Hour,
|
||||
// GC: basicauth.GC{
|
||||
// Every: 3 * time.Hour,
|
||||
// },
|
||||
// Allow: basicauth.AllowUsers(users),
|
||||
// }
|
||||
// auth := basicauth.New(opts)
|
||||
// app.Use(auth)
|
||||
//
|
||||
// opts := basicauth.Options{
|
||||
// Realm: basicauth.DefaultRealm,
|
||||
// ErrorHandler: basicauth.DefaultErrorHandler,
|
||||
// MaxAge: 2 * time.Hour,
|
||||
// GC: basicauth.GC{
|
||||
// Every: 3 * time.Hour,
|
||||
// },
|
||||
// Allow: basicauth.AllowUsers(users),
|
||||
// }
|
||||
// auth := basicauth.New(opts)
|
||||
// app.Use(auth)
|
||||
//
|
||||
// Access the user in the route handler with: ctx.User().GetRaw().(*myCustomType).
|
||||
//
|
||||
@@ -238,16 +240,18 @@ func New(opts Options) context.Handler {
|
||||
// are required as they are compared against the user input
|
||||
// when access to protected resource is requested.
|
||||
// A user list can defined with one of the following values:
|
||||
// map[string]string form of: {username:password, ...}
|
||||
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
||||
// []T which T completes the User interface, where T is a struct value
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// map[string]string form of: {username:password, ...}
|
||||
// map[string]interface{} form of: {"username": {"password": "...", "other_field": ...}, ...}
|
||||
// []T which T completes the User interface, where T is a struct value
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// Usage:
|
||||
// auth := Default(map[string]string{
|
||||
// "admin": "admin",
|
||||
// "john": "p@ss",
|
||||
// })
|
||||
//
|
||||
// auth := Default(map[string]string{
|
||||
// "admin": "admin",
|
||||
// "john": "p@ss",
|
||||
// })
|
||||
func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
||||
opts := Options{
|
||||
Realm: DefaultRealm,
|
||||
@@ -260,7 +264,8 @@ func Default(users interface{}, userOpts ...UserAuthOption) context.Handler {
|
||||
// a filename to load the users from.
|
||||
//
|
||||
// Usage:
|
||||
// auth := Load("users.yml")
|
||||
//
|
||||
// auth := Load("users.yml")
|
||||
func Load(jsonOrYamlFilename string, userOpts ...UserAuthOption) context.Handler {
|
||||
opts := Options{
|
||||
Realm: DefaultRealm,
|
||||
|
||||
@@ -3,7 +3,7 @@ package basicauth
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
// ReadFile can be used to customize the way the
|
||||
// AllowUsersFile function is loading the filename from.
|
||||
// Example of usage: embedded users.yml file.
|
||||
// Defaults to the `ioutil.ReadFile` which reads the file from the physical disk.
|
||||
var ReadFile = ioutil.ReadFile
|
||||
// Defaults to the `os.ReadFile` which reads the file from the physical disk.
|
||||
var ReadFile = os.ReadFile
|
||||
|
||||
// User is a partial part of the iris.User interface.
|
||||
// It's used to declare a static slice of registered User for authentication.
|
||||
@@ -48,10 +48,11 @@ type UserAuthOption func(*UserAuthOptions)
|
||||
// See https://www.usenix.org/legacy/event/usenix99/provos/provos.pdf.
|
||||
//
|
||||
// Usage:
|
||||
// Default(..., BCRYPT) OR
|
||||
// Load(..., BCRYPT) OR
|
||||
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
||||
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
|
||||
//
|
||||
// Default(..., BCRYPT) OR
|
||||
// Load(..., BCRYPT) OR
|
||||
// Options.Allow = AllowUsers(..., BCRYPT) OR
|
||||
// OPtions.Allow = AllowUsersFile(..., BCRYPT)
|
||||
func BCRYPT(opts *UserAuthOptions) {
|
||||
opts.ComparePassword = func(stored, userPassword string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(stored), []byte(userPassword))
|
||||
@@ -75,10 +76,11 @@ func toUserAuthOptions(opts []UserAuthOption) (options UserAuthOptions) {
|
||||
|
||||
// AllowUsers is an AuthFunc which authenticates user input based on a (static) user list.
|
||||
// The "users" input parameter can be one of the following forms:
|
||||
// map[string]string e.g. {username: password, username: password...}.
|
||||
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
||||
// []T which T completes the User interface.
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// map[string]string e.g. {username: password, username: password...}.
|
||||
// []map[string]interface{} e.g. []{"username": "...", "password": "...", "other_field": ...}, ...}.
|
||||
// []T which T completes the User interface.
|
||||
// []T which T contains at least Username and Password fields.
|
||||
//
|
||||
// Usage:
|
||||
// New(Options{Allow: AllowUsers(..., [BCRYPT])})
|
||||
@@ -155,15 +157,17 @@ func userMap(usernamePassword map[string]string, opts ...UserAuthOption) AuthFun
|
||||
// loaded from a file on initialization.
|
||||
//
|
||||
// Example Code:
|
||||
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
||||
//
|
||||
// New(Options{Allow: AllowUsersFile("users.yml", BCRYPT)})
|
||||
//
|
||||
// The users.yml file looks like the following:
|
||||
// - username: kataras
|
||||
// password: kataras_pass
|
||||
// age: 27
|
||||
// role: admin
|
||||
// - username: makis
|
||||
// password: makis_password
|
||||
// ...
|
||||
// - username: kataras
|
||||
// password: kataras_pass
|
||||
// age: 27
|
||||
// role: admin
|
||||
// - username: makis
|
||||
// password: makis_password
|
||||
// ...
|
||||
func AllowUsersFile(jsonOrYamlFilename string, opts ...UserAuthOption) AuthFunc {
|
||||
var (
|
||||
usernamePassword map[string]string
|
||||
|
||||
@@ -2,7 +2,6 @@ package basicauth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
@@ -164,7 +163,7 @@ func TestAllowUsers(t *testing.T) {
|
||||
|
||||
// Test YAML user loading with b-encrypted passwords.
|
||||
func TestAllowUsersFile(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "*users.yml")
|
||||
f, err := os.CreateTemp("", "*users.yml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -85,17 +85,18 @@ type (
|
||||
// please refer to: https://github.com/iris-contrib/middleware repository instead.
|
||||
//
|
||||
// Example Code:
|
||||
// import "github.com/kataras/iris/v12/middleware/cors"
|
||||
// import "github.com/kataras/iris/v12/x/errors"
|
||||
//
|
||||
// app.UseRouter(cors.New().
|
||||
// HandleErrorFunc(func(ctx iris.Context, err error) {
|
||||
// errors.FailedPrecondition.Err(ctx, err)
|
||||
// }).
|
||||
// ExtractOriginFunc(cors.StrictOriginExtractor).
|
||||
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
|
||||
// AllowOrigin("domain1.com,domain2.com,domain3.com").
|
||||
// Handler())
|
||||
// import "github.com/kataras/iris/v12/middleware/cors"
|
||||
// import "github.com/kataras/iris/v12/x/errors"
|
||||
//
|
||||
// app.UseRouter(cors.New().
|
||||
// HandleErrorFunc(func(ctx iris.Context, err error) {
|
||||
// errors.FailedPrecondition.Err(ctx, err)
|
||||
// }).
|
||||
// ExtractOriginFunc(cors.StrictOriginExtractor).
|
||||
// ReferrerPolicy(cors.NoReferrerWhenDowngrade).
|
||||
// AllowOrigin("domain1.com,domain2.com,domain3.com").
|
||||
// Handler())
|
||||
func New() *CORS {
|
||||
return &CORS{
|
||||
extractOriginFunc: DefaultOriginExtractor,
|
||||
|
||||
@@ -13,11 +13,12 @@ import (
|
||||
// The Iris server SHOULD run under HTTP/2 and clients too.
|
||||
//
|
||||
// Usage:
|
||||
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
||||
// [...]
|
||||
// app := iris.New()
|
||||
// grpcServer := grpc.NewServer()
|
||||
// app.WrapRouter(grpcWrapper.New(grpcServer))
|
||||
//
|
||||
// import grpcWrapper "github.com/kataras/iris/v12/middleware/grpc"
|
||||
// [...]
|
||||
// app := iris.New()
|
||||
// grpcServer := grpc.NewServer()
|
||||
// app.WrapRouter(grpcWrapper.New(grpcServer))
|
||||
func New(grpcServer http.Handler) router.WrapperFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request, mux http.HandlerFunc) {
|
||||
if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {
|
||||
|
||||
@@ -3,7 +3,7 @@ package hcaptcha
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
@@ -70,7 +70,9 @@ func New(secret string, options ...Option) context.Handler {
|
||||
|
||||
// Handler is the HTTP route middleware featured hcaptcha validation.
|
||||
// It calls the `SiteVerify` method and fires the "next" when user completed the hcaptcha successfully,
|
||||
// otherwise it calls the Client's `FailureHandler`.
|
||||
//
|
||||
// otherwise it calls the Client's `FailureHandler`.
|
||||
//
|
||||
// The hcaptcha's `Response` (which contains any `ErrorCodes`)
|
||||
// is saved on the Request's Context (see `GetResponseFromContext`).
|
||||
func (c *Client) Handler(ctx *context.Context) {
|
||||
@@ -113,7 +115,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||
|
||||
@@ -55,14 +55,14 @@ var _ jwt.Blocklist = (*Blocklist)(nil)
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// blocklist := NewBlocklist()
|
||||
// blocklist.ClientOptions.Addr = ...
|
||||
// err := blocklist.Connect()
|
||||
// blocklist := NewBlocklist()
|
||||
// blocklist.ClientOptions.Addr = ...
|
||||
// err := blocklist.Connect()
|
||||
//
|
||||
// And register it:
|
||||
//
|
||||
// verifier := jwt.NewVerifier(...)
|
||||
// verifier.Blocklist = blocklist
|
||||
// verifier := jwt.NewVerifier(...)
|
||||
// verifier.Blocklist = blocklist
|
||||
func NewBlocklist() *Blocklist {
|
||||
return &Blocklist{
|
||||
GetKey: defaultGetKey,
|
||||
|
||||
@@ -31,8 +31,8 @@ type Signer struct {
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// signer := NewSigner(HS256, secret, 15*time.Minute)
|
||||
// token, err := signer.Sign(userClaims{Username: "kataras"})
|
||||
// signer := NewSigner(HS256, secret, 15*time.Minute)
|
||||
// token, err := signer.Sign(userClaims{Username: "kataras"})
|
||||
func NewSigner(signatureAlg Alg, signatureKey interface{}, maxAge time.Duration) *Signer {
|
||||
if signatureAlg == HS256 {
|
||||
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
||||
|
||||
@@ -61,24 +61,31 @@ type Verifier struct {
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// verifier := NewVerifier(HS256, secret)
|
||||
// OR
|
||||
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
||||
// verifier := NewVerifier(HS256, secret)
|
||||
//
|
||||
// claimsGetter := func() interface{} { return new(userClaims) }
|
||||
// middleware := verifier.Verify(claimsGetter)
|
||||
// OR
|
||||
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
||||
//
|
||||
// verifier := NewVerifier(HS256, secret, Expected{Issuer: "my-app"})
|
||||
//
|
||||
// claimsGetter := func() interface{} { return new(userClaims) }
|
||||
// middleware := verifier.Verify(claimsGetter)
|
||||
//
|
||||
// OR
|
||||
//
|
||||
// middleware := verifier.Verify(claimsGetter, Expected{Issuer: "my-app"})
|
||||
//
|
||||
// Register the middleware, e.g.
|
||||
// app.Use(middleware)
|
||||
//
|
||||
// app.Use(middleware)
|
||||
//
|
||||
// Get the claims:
|
||||
// claims := jwt.Get(ctx).(*userClaims)
|
||||
// username := claims.Username
|
||||
//
|
||||
// claims := jwt.Get(ctx).(*userClaims)
|
||||
// username := claims.Username
|
||||
//
|
||||
// Get the context user:
|
||||
// username, err := ctx.User().GetUsername()
|
||||
//
|
||||
// username, err := ctx.User().GetUsername()
|
||||
func NewVerifier(signatureAlg Alg, signatureKey interface{}, validators ...TokenValidator) *Verifier {
|
||||
if signatureAlg == HS256 {
|
||||
// A tiny helper if the end-developer uses string instead of []byte for hmac keys.
|
||||
|
||||
@@ -166,11 +166,12 @@ func Query(paramName string) Option {
|
||||
// to determinate the method to override with.
|
||||
//
|
||||
// Use cases:
|
||||
// 1. When need to check only for headers and ignore other fields:
|
||||
// New(Only(Headers("X-Custom-Header")))
|
||||
//
|
||||
// 2. When need to check only for (first) form field and (second) custom getter:
|
||||
// New(Only(FormField("fieldName"), Getter(...)))
|
||||
// 1. When need to check only for headers and ignore other fields:
|
||||
// New(Only(Headers("X-Custom-Header")))
|
||||
//
|
||||
// 2. When need to check only for (first) form field and (second) custom getter:
|
||||
// New(Only(FormField("fieldName"), Getter(...)))
|
||||
func Only(o ...Option) Option {
|
||||
return func(opts *options) {
|
||||
opts.getters = opts.getters[0:0]
|
||||
@@ -185,7 +186,6 @@ func Only(o ...Option) Option {
|
||||
// that do not support certain HTTP operations such as DELETE or PUT for security reasons.
|
||||
// This wrapper will accept a method, based on criteria, to override the POST method with.
|
||||
//
|
||||
//
|
||||
// Read more at:
|
||||
// https://github.com/kataras/iris/issues/1325
|
||||
func New(opt ...Option) router.WrapperFunc {
|
||||
|
||||
@@ -34,12 +34,13 @@ type Options struct {
|
||||
// for security reasons.
|
||||
//
|
||||
// Example Code:
|
||||
// app.Get("/health", modrevision.New(modrevision.Options{
|
||||
// ServerName: "Iris Server",
|
||||
// Env: "development",
|
||||
// Developer: "kataras",
|
||||
// TimeLocation: time.FixedZone("Greece/Athens", 10800),
|
||||
// }))
|
||||
//
|
||||
// app.Get("/health", modrevision.New(modrevision.Options{
|
||||
// ServerName: "Iris Server",
|
||||
// Env: "development",
|
||||
// Developer: "kataras",
|
||||
// TimeLocation: time.FixedZone("Greece/Athens", 7200),
|
||||
// }))
|
||||
func New(opts Options) context.Handler {
|
||||
buildTime, buildRevision := context.BuildTime, context.BuildRevision
|
||||
if opts.UnixTime {
|
||||
|
||||
@@ -41,7 +41,8 @@ var profileDescriptions = map[string]string{
|
||||
// New returns a new pprof (profile, cmdline, symbol, goroutine, heap, threadcreate, debug/block) Middleware.
|
||||
// Note: Route MUST have the last named parameter wildcard named '{action:path}'.
|
||||
// Example:
|
||||
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
||||
//
|
||||
// app.HandleMany("GET", "/debug/pprof /debug/pprof/{action:path}", pprof.New())
|
||||
func New() context.Handler {
|
||||
return func(ctx *context.Context) {
|
||||
if action := ctx.Params().Get("action"); action != "" {
|
||||
|
||||
@@ -3,7 +3,7 @@ package recaptcha
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
@@ -50,7 +50,9 @@ func New(secret string) context.Handler {
|
||||
}
|
||||
|
||||
// SiteVerify accepts context and the secret key(https://www.google.com/recaptcha)
|
||||
// and returns the google's recaptcha response, if `response.Success` is true
|
||||
//
|
||||
// and returns the google's recaptcha response, if `response.Success` is true
|
||||
//
|
||||
// then validation passed.
|
||||
//
|
||||
// Use `New` for middleware use instead.
|
||||
@@ -74,7 +76,7 @@ func SiteVerify(ctx *context.Context, secret string) (response Response) {
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
body, err := io.ReadAll(r.Body)
|
||||
r.Body.Close()
|
||||
if err != nil {
|
||||
response.ErrorCodes = append(response.ErrorCodes, err.Error())
|
||||
@@ -113,22 +115,24 @@ var recaptchaForm = `<form action="%s" method="POST">
|
||||
// Example Code:
|
||||
//
|
||||
// Method: "POST" | Path: "/contact"
|
||||
// func postContact(ctx *context.Context) {
|
||||
// // [...]
|
||||
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
||||
//
|
||||
// if response.Success {
|
||||
// // [your action here, i.e sendEmail(...)]
|
||||
// }
|
||||
// func postContact(ctx *context.Context) {
|
||||
// // [...]
|
||||
// response := recaptcha.SiteVerify(ctx, recaptchaSecret)
|
||||
//
|
||||
// ctx.JSON(response)
|
||||
// }
|
||||
// if response.Success {
|
||||
// // [your action here, i.e sendEmail(...)]
|
||||
// }
|
||||
//
|
||||
// ctx.JSON(response)
|
||||
// }
|
||||
//
|
||||
// Method: "GET" | Path: "/contact"
|
||||
// func getContact(ctx *context.Context) {
|
||||
// // render the recaptcha form
|
||||
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
||||
// }
|
||||
//
|
||||
// func getContact(ctx *context.Context) {
|
||||
// // render the recaptcha form
|
||||
// ctx.HTML(recaptcha.GetFormHTML(recaptchaPublic, "/contact"))
|
||||
// }
|
||||
func GetFormHTML(dataSiteKey string, postActionRelativePath string) string {
|
||||
return fmt.Sprintf(recaptchaForm, postActionRelativePath, dataSiteKey)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user