1
0
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:
Gerasimos (Makis) Maropoulos
2022-06-17 22:03:18 +03:00
parent 20d2855a66
commit ef2643b046
108 changed files with 1069 additions and 1021 deletions

View File

@@ -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

View File

@@ -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.

View File

@@ -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,

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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,

View File

@@ -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") {

View File

@@ -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())

View File

@@ -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,

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 != "" {

View File

@@ -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)
}