aboutsummaryrefslogtreecommitdiff
path: root/example/example.go
diff options
context:
space:
mode:
Diffstat (limited to 'example/example.go')
-rw-r--r--example/example.go733
1 files changed, 0 insertions, 733 deletions
diff --git a/example/example.go b/example/example.go
deleted file mode 100644
index 037c17a..0000000
--- a/example/example.go
+++ /dev/null
@@ -1,733 +0,0 @@
-// SPDX-FileCopyrightText: 2021 M. Shulhan <ms@kilabit.info>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-// Package example provide an example how to use the Gorankusu library from
-// setting it up to creating targets.
-//
-// To run the example, execute
-//
-// $ go run ./internal/cmd/gorankusu
-//
-// It will run a web user interface at http://127.0.0.1:8217 .
-package example
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "mime/multipart"
- "net/http"
- "net/url"
- "sync"
- "time"
-
- liberrors "github.com/shuLhan/share/lib/errors"
- libhttp "github.com/shuLhan/share/lib/http"
- "github.com/shuLhan/share/lib/mlog"
- "github.com/shuLhan/share/lib/websocket"
- vegeta "github.com/tsenart/vegeta/v12/lib"
-
- "git.sr.ht/~shulhan/gorankusu"
-)
-
-const (
- pathExample = `/example`
- pathExampleError = `/example/error`
- pathExampleNamePage = `/example/:name/page`
- pathExampleRawbodyJSON = `/example/rawbody/json`
- pathExampleUpload = `/example/upload`
-)
-
-const (
- websocketAddress = "127.0.0.1:28240"
-)
-
-type requestResponse struct {
- Method string
- URL string
- Headers http.Header
- Form url.Values
- MultipartForm *multipart.Form
- Body string
-}
-
-// Example contains an example how to use Gorankusu programmatically.
-type Example struct {
- gorankusu *gorankusu.Gorankusu
- wsServer *websocket.Server
-
- targetExampleErrorGet vegeta.Target
- targetExampleGet vegeta.Target
- targetExamplePostForm vegeta.Target
-}
-
-// New create, initialize, and setup an example service.
-func New() (ex *Example, err error) {
- env := &gorankusu.Environment{
- ResultsDir: "example/testdata/",
- ResultsSuffix: "example",
- }
-
- ex = &Example{}
-
- ex.gorankusu, err = gorankusu.New(env)
- if err != nil {
- return nil, fmt.Errorf("example: New: %w", err)
- }
-
- err = ex.registerEndpoints()
- if err != nil {
- return nil, fmt.Errorf("example: New: %w", err)
- }
-
- // Create and register endpoint for WebSocket server.
- wsOpts := &websocket.ServerOptions{
- Address: websocketAddress,
- }
-
- ex.wsServer = websocket.NewServer(wsOpts)
-
- err = ex.registerWebSocketEndpoints()
- if err != nil {
- return nil, fmt.Errorf("example: New: %w", err)
- }
-
- // Register target for testing HTTP endpoints.
- err = ex.registerTargetHTTP()
- if err != nil {
- return nil, fmt.Errorf("example: New: %w", err)
- }
-
- // Register target for testing WebSocket endpoints.
- err = ex.registerTargetWebSocket()
- if err != nil {
- return nil, fmt.Errorf("example: New: %w", err)
- }
-
- err = ex.registerNavLinks()
- if err != nil {
- return nil, fmt.Errorf("example: New: %w", err)
- }
-
- return ex, nil
-}
-
-// Start the Example servers.
-func (ex *Example) Start() (err error) {
- go func() {
- err = ex.wsServer.Start()
- if err != nil {
- mlog.Errf(`example.Start: %s`, err)
- }
- }()
-
- return ex.gorankusu.Start()
-}
-
-// Stop the Example servers.
-func (ex *Example) Stop() {
- ex.wsServer.Stop()
- ex.gorankusu.Stop()
-}
-
-// registerEndpoints register HTTP endpoints for testing.
-func (ex *Example) registerEndpoints() (err error) {
- err = ex.gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
- Method: libhttp.RequestMethodGet,
- Path: pathExample,
- RequestType: libhttp.RequestTypeQuery,
- ResponseType: libhttp.ResponseTypeJSON,
- Call: ex.pathExampleGet,
- })
- if err != nil {
- return err
- }
-
- err = ex.gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
- Method: libhttp.RequestMethodGet,
- Path: pathExampleError,
- RequestType: libhttp.RequestTypeQuery,
- ResponseType: libhttp.ResponseTypeJSON,
- Call: ex.pathExampleErrorGet,
- })
- if err != nil {
- return err
- }
-
- err = ex.gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
- Method: libhttp.RequestMethodPost,
- Path: pathExample,
- RequestType: libhttp.RequestTypeForm,
- ResponseType: libhttp.ResponseTypeJSON,
- Call: ex.pathExamplePost,
- })
-
- err = ex.gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
- Method: libhttp.RequestMethodPost,
- Path: pathExampleNamePage,
- RequestType: libhttp.RequestTypeJSON,
- ResponseType: libhttp.ResponseTypeJSON,
- Call: ex.pathExamplePost,
- })
-
- err = ex.gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
- Method: libhttp.RequestMethodPost,
- Path: pathExampleRawbodyJSON,
- RequestType: libhttp.RequestTypeJSON,
- ResponseType: libhttp.ResponseTypeJSON,
- Call: ex.pathExampleRawbodyJSON,
- })
-
- err = ex.gorankusu.Httpd.RegisterEndpoint(&libhttp.Endpoint{
- Method: libhttp.RequestMethodPost,
- Path: pathExampleUpload,
- RequestType: libhttp.RequestTypeMultipartForm,
- ResponseType: libhttp.ResponseTypeJSON,
- Call: ex.pathExampleUpload,
- })
-
- return err
-}
-
-func (ex *Example) registerWebSocketEndpoints() (err error) {
- err = ex.wsServer.RegisterTextHandler(http.MethodGet, pathExample,
- ex.handleWSExampleGet)
- if err != nil {
- return err
- }
- return nil
-}
-
-func (ex *Example) registerTargetHTTP() (err error) {
- var targetHTTP = &gorankusu.Target{
- Name: "Example HTTP",
- Hint: "This section provide an example of HTTP endpoints that can be tested and attacked.",
- BaseURL: fmt.Sprintf(`http://%s`, ex.gorankusu.Env.ListenAddress),
- Opts: &gorankusu.AttackOptions{
- Duration: 300 * time.Second,
- RatePerSecond: 1,
- },
- Vars: gorankusu.KeyFormInput{
- "A": gorankusu.FormInput{
- Label: "A",
- Hint: "This is the global variabel for all HTTP targets below.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "1",
- },
- },
- HTTPTargets: []*gorankusu.HTTPTarget{{
- Name: "HTTP Get",
- Hint: fmt.Sprintf("Test or attack endpoint %q using HTTP GET.", pathExample),
- Method: libhttp.RequestMethodGet,
- Path: pathExample,
- RequestType: libhttp.RequestTypeQuery,
- Headers: gorankusu.KeyFormInput{
- "X-Get": gorankusu.FormInput{
- Label: "X-Get",
- Hint: "Custom HTTP header to be send.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "1.1",
- },
- },
- Params: gorankusu.KeyFormInput{
- "Param1": gorankusu.FormInput{
- Label: "Param1",
- Hint: "Parameter with number.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "1",
- },
- },
- Run: ex.runExampleGet,
- AllowAttack: true,
- Attack: ex.attackExampleGet,
- PreAttack: ex.preattackExampleGet,
- }, {
- Name: "HTTP Error Get",
- Hint: fmt.Sprintf("Test error on endpoint %q using HTTP GET.", pathExampleError),
- Method: libhttp.RequestMethodGet,
- Path: pathExampleError,
- RequestType: libhttp.RequestTypeQuery,
- Headers: gorankusu.KeyFormInput{
- "X-Get": gorankusu.FormInput{
- Label: "X-Get",
- Hint: "Custom HTTP header to be send.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "1.1",
- },
- },
- Params: gorankusu.KeyFormInput{
- "Param1": gorankusu.FormInput{
- Label: "Param1",
- Hint: "Parameter with number.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "1",
- },
- },
- Run: ex.runExampleGet,
- AllowAttack: true,
- Attack: ex.attackExampleErrorGet,
- PreAttack: ex.preattackExampleErrorGet,
- }, {
- Name: "HTTP Post Form",
- Hint: fmt.Sprintf("Test or attack endpoint %q using HTTP POST.", pathExample),
- Method: libhttp.RequestMethodPost,
- Path: pathExample,
- RequestType: libhttp.RequestTypeForm,
- Headers: gorankusu.KeyFormInput{
- "X-PostForm": gorankusu.FormInput{
- Label: "X-PostForm",
- Hint: "Custom HTTP header to be send.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "1",
- },
- },
- Params: gorankusu.KeyFormInput{
- "Param1": gorankusu.FormInput{
- Label: "Param1",
- Hint: "Parameter with number.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "1",
- },
- "Param2": gorankusu.FormInput{
- Label: "Param2",
- Hint: "Parameter with string.",
- Kind: gorankusu.FormInputKindString,
- Value: "a string",
- },
- },
- Run: ex.runExamplePostForm,
- AllowAttack: true,
- PreAttack: ex.preattackExamplePostForm,
- Attack: ex.attackExamplePostForm,
- }, {
- Name: "HTTP free form",
- Hint: fmt.Sprintf("Test endpoint %q using custom HTTP method and/or content type.", pathExample),
- Method: libhttp.RequestMethodGet,
- Path: pathExample,
- RequestType: libhttp.RequestTypeForm,
- Headers: gorankusu.KeyFormInput{
- "X-FreeForm": gorankusu.FormInput{
- Label: "X-FreeForm",
- Hint: "Custom HTTP header to be send.",
- Kind: gorankusu.FormInputKindString,
- Value: "1",
- },
- },
- Params: gorankusu.KeyFormInput{
- "Param1": gorankusu.FormInput{
- Label: "Param1",
- Hint: "Parameter with number.",
- Kind: gorankusu.FormInputKindNumber,
- Value: "123",
- },
- },
- IsCustomizable: true,
- }, {
- Name: `HTTP Post path binding`,
- Hint: `Test parameter with parameter in path`,
- Method: libhttp.RequestMethodPost,
- Path: pathExampleNamePage,
- RequestType: libhttp.RequestTypeJSON,
- Params: gorankusu.KeyFormInput{
- `name`: gorankusu.FormInput{
- Label: `Name`,
- Hint: `This parameter send in path.`,
- Value: `testname`,
- },
- `id`: gorankusu.FormInput{
- Label: `ID`,
- Hint: `This parameter send in body as JSON.`,
- Value: `123`,
- },
- },
- }, {
- Name: `HTTP raw body - JSON`,
- Hint: `Test POST request with manually input raw JSON.`,
- Method: libhttp.RequestMethodPost,
- Path: pathExampleRawbodyJSON,
- RequestType: libhttp.RequestTypeJSON,
- WithRawBody: true,
- }, {
- Name: `HTTP upload`,
- Hint: `Test uploading file`,
- Method: libhttp.RequestMethodPost,
- Path: pathExampleUpload,
- RequestType: libhttp.RequestTypeMultipartForm,
- Params: gorankusu.KeyFormInput{
- `file`: gorankusu.FormInput{
- Label: `File`,
- Hint: `File to be uploaded.`,
- Kind: gorankusu.FormInputKindFile,
- FormDataName: func(key string) string {
- if key == gorankusu.FormDataFilename {
- return `name`
- }
- return key
- },
- },
- `agree`: gorankusu.FormInput{
- Label: `Agree`,
- Hint: `Additional parameter along file.`,
- Kind: gorankusu.FormInputKindBoolean,
- },
- },
- }},
- }
-
- err = ex.gorankusu.RegisterTarget(targetHTTP)
- if err != nil {
- return err
- }
- return nil
-}
-
-func (ex *Example) registerTargetWebSocket() (err error) {
- targetWebSocket := &gorankusu.Target{
- Name: "Example WebSocket",
- Hint: "This section provide an example of WebSocket endpoints that can be tested.",
- BaseURL: fmt.Sprintf(`ws://%s`, websocketAddress),
- Opts: &gorankusu.AttackOptions{},
- Vars: gorankusu.KeyFormInput{
- "WebSocketVar": gorankusu.FormInput{
- Label: "WebSocketVar",
- Kind: gorankusu.FormInputKindString,
- Value: "hello",
- },
- },
- WebSocketTargets: []*gorankusu.WebSocketTarget{{
- Name: "Similar to HTTP GET",
- Hint: "Test WebSocket endpoint with parameters.",
- Params: gorankusu.KeyFormInput{
- "Param1": gorankusu.FormInput{
- Label: "Param1",
- Hint: "Parameter with kind is number.",
- Kind: "number",
- Value: "123",
- },
- },
- Run: ex.runWebSocketGet,
- }},
- }
-
- err = ex.gorankusu.RegisterTarget(targetWebSocket)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (ex *Example) registerNavLinks() (err error) {
- logp := "registerNavLinks"
-
- err = ex.gorankusu.RegisterNavLink(&gorankusu.NavLink{
- Text: "Link in IFrame",
- Href: "https://git.sr.ht/~shulhan/gorankusu",
- OpenInIFrame: true,
- })
- if err != nil {
- return fmt.Errorf("%s: %w", logp, err)
- }
-
- err = ex.gorankusu.RegisterNavLink(&gorankusu.NavLink{
- Text: "Link in new window",
- Href: "https://git.sr.ht/~shulhan/gorankusu",
- })
- if err != nil {
- return fmt.Errorf("%s: %w", logp, err)
- }
-
- return nil
-}
-
-func (ex *Example) pathExampleGet(epr *libhttp.EndpointRequest) ([]byte, error) {
- data := &requestResponse{
- Method: epr.HttpRequest.Method,
- URL: epr.HttpRequest.URL.String(),
- Headers: epr.HttpRequest.Header,
- Form: epr.HttpRequest.Form,
- MultipartForm: epr.HttpRequest.MultipartForm,
- Body: string(epr.RequestBody),
- }
-
- res := libhttp.EndpointResponse{}
- res.Code = http.StatusOK
- res.Message = pathExample
- res.Data = data
-
- return json.Marshal(&res)
-}
-
-func (ex *Example) pathExampleErrorGet(_ *libhttp.EndpointRequest) ([]byte, error) {
- return nil, liberrors.Internal(fmt.Errorf("server error"))
-}
-
-func (ex *Example) pathExamplePost(epr *libhttp.EndpointRequest) (resb []byte, err error) {
- data := &requestResponse{
- Method: epr.HttpRequest.Method,
- URL: epr.HttpRequest.URL.String(),
- Headers: epr.HttpRequest.Header,
- Form: epr.HttpRequest.Form,
- MultipartForm: epr.HttpRequest.MultipartForm,
- Body: string(epr.RequestBody),
- }
-
- res := libhttp.EndpointResponse{}
- res.Code = http.StatusOK
- res.Message = pathExample
- res.Data = data
-
- return json.Marshal(&res)
-}
-
-func (ex *Example) pathExampleRawbodyJSON(epr *libhttp.EndpointRequest) (resbody []byte, err error) {
- var (
- logp = `pathExampleRawbodyJSON`
- data map[string]any
- )
-
- err = json.Unmarshal(epr.RequestBody, &data)
- if err != nil {
- return nil, fmt.Errorf(`%s: %w`, logp, err)
- }
-
- var res = libhttp.EndpointResponse{}
- res.Code = http.StatusOK
- res.Data = data
-
- resbody, err = json.Marshal(&res)
- return resbody, err
-}
-
-func (ex *Example) pathExampleUpload(epr *libhttp.EndpointRequest) (resb []byte, err error) {
- var logp = `pathExampleUpload`
-
- var res = libhttp.EndpointResponse{}
-
- res.Code = http.StatusOK
- res.Data = epr.HttpRequest.MultipartForm.Value
-
- resb, err = json.Marshal(res)
- if err != nil {
- return nil, fmt.Errorf(`%s: %w`, logp, err)
- }
-
- return resb, nil
-}
-
-func (ex *Example) runExampleGet(req *gorankusu.RunRequest) (res *gorankusu.RunResponse, err error) {
- if req.Target.HTTPClient == nil {
- var httpcOpts = &libhttp.ClientOptions{
- ServerUrl: req.Target.BaseURL,
- AllowInsecure: true,
- }
- req.Target.HTTPClient = libhttp.NewClient(httpcOpts)
- }
-
- res = &gorankusu.RunResponse{}
-
- var (
- headers = req.HTTPTarget.Headers.ToHTTPHeader()
- params = req.HTTPTarget.Params.ToURLValues()
-
- httpRequest *http.Request
- )
-
- httpRequest, err = req.Target.HTTPClient.GenerateHttpRequest(
- req.HTTPTarget.Method,
- req.HTTPTarget.Path,
- req.HTTPTarget.RequestType,
- headers,
- params,
- )
- if err != nil {
- return nil, err
- }
-
- err = res.SetHTTPRequest(req.HTTPTarget.RequestDumper, httpRequest)
- if err != nil {
- return nil, err
- }
-
- var httpResponse *http.Response
-
- httpResponse, _, err = req.Target.HTTPClient.Do(httpRequest)
- if err != nil {
- return nil, err
- }
-
- err = res.SetHTTPResponse(req.HTTPTarget.ResponseDumper, httpResponse)
- if err != nil {
- return nil, err
- }
-
- return res, nil
-}
-
-func (ex *Example) preattackExampleErrorGet(rr *gorankusu.RunRequest) {
- ex.targetExampleErrorGet = vegeta.Target{
- Method: rr.HTTPTarget.Method.String(),
- URL: fmt.Sprintf("%s%s", rr.Target.BaseURL, rr.HTTPTarget.Path),
- Header: rr.HTTPTarget.Headers.ToHTTPHeader(),
- }
-
- q := rr.HTTPTarget.Params.ToURLValues().Encode()
- if len(q) > 0 {
- ex.targetExampleErrorGet.URL += "?" + q
- }
-
- fmt.Printf("preattackExampleErrorGet: %+v\n", ex.targetExampleErrorGet)
-}
-
-func (ex *Example) preattackExampleGet(rr *gorankusu.RunRequest) {
- ex.targetExampleGet = vegeta.Target{
- Method: rr.HTTPTarget.Method.String(),
- URL: fmt.Sprintf("%s%s", rr.Target.BaseURL, rr.HTTPTarget.Path),
- Header: rr.HTTPTarget.Headers.ToHTTPHeader(),
- }
-
- q := rr.HTTPTarget.Params.ToURLValues().Encode()
- if len(q) > 0 {
- ex.targetExampleGet.URL += "?" + q
- }
-
- fmt.Printf("preattackExampleGet: %+v\n", ex.targetExampleGet)
-}
-
-func (ex *Example) attackExampleErrorGet(rr *gorankusu.RunRequest) vegeta.Targeter {
- return func(tgt *vegeta.Target) error {
- rr.HTTPTarget.Lock()
- *tgt = ex.targetExampleErrorGet
- rr.HTTPTarget.Unlock()
- return nil
- }
-}
-
-func (ex *Example) attackExampleGet(rr *gorankusu.RunRequest) vegeta.Targeter {
- return func(tgt *vegeta.Target) error {
- rr.HTTPTarget.Lock()
- *tgt = ex.targetExampleGet
- rr.HTTPTarget.Unlock()
- return nil
- }
-}
-
-func (ex *Example) runExamplePostForm(req *gorankusu.RunRequest) (res *gorankusu.RunResponse, err error) {
- if req.Target.HTTPClient == nil {
- httpcOpts := &libhttp.ClientOptions{
- ServerUrl: req.Target.BaseURL,
- AllowInsecure: true,
- }
- req.Target.HTTPClient = libhttp.NewClient(httpcOpts)
- }
-
- res = &gorankusu.RunResponse{}
-
- headers := req.HTTPTarget.Headers.ToHTTPHeader()
- params := req.HTTPTarget.Params.ToURLValues()
-
- httpRequest, err := req.Target.HTTPClient.GenerateHttpRequest(
- req.HTTPTarget.Method,
- req.HTTPTarget.Path,
- req.HTTPTarget.RequestType,
- headers,
- params,
- )
- if err != nil {
- return nil, err
- }
-
- err = res.SetHTTPRequest(req.HTTPTarget.RequestDumper, httpRequest)
- if err != nil {
- return nil, err
- }
-
- httpResponse, _, err := req.Target.HTTPClient.Do(httpRequest)
- if err != nil {
- return nil, err
- }
-
- err = res.SetHTTPResponse(req.HTTPTarget.ResponseDumper, httpResponse)
- if err != nil {
- return nil, err
- }
-
- return res, nil
-}
-
-func (ex *Example) preattackExamplePostForm(rr *gorankusu.RunRequest) {
- ex.targetExamplePostForm = vegeta.Target{
- Method: rr.HTTPTarget.Method.String(),
- URL: fmt.Sprintf("%s%s", rr.Target.BaseURL, rr.HTTPTarget.Path),
- Header: rr.HTTPTarget.Headers.ToHTTPHeader(),
- }
-
- q := rr.HTTPTarget.Params.ToURLValues().Encode()
- if len(q) > 0 {
- ex.targetExamplePostForm.Body = []byte(q)
- }
-
- fmt.Printf("preattackExamplePostForm: %+v\n", ex.targetExamplePostForm)
-}
-
-func (ex *Example) attackExamplePostForm(rr *gorankusu.RunRequest) vegeta.Targeter {
- return func(tgt *vegeta.Target) error {
- rr.HTTPTarget.Lock()
- *tgt = ex.targetExamplePostForm
- rr.HTTPTarget.Unlock()
- return nil
- }
-}
-
-func (ex *Example) handleWSExampleGet(_ context.Context, req *websocket.Request) (res websocket.Response) {
- res.ID = req.ID
- res.Code = http.StatusOK
- res.Body = req.Body
- return res
-}
-
-func (ex *Example) runWebSocketGet(rr *gorankusu.RunRequest) (res interface{}, err error) {
- var wg sync.WaitGroup
-
- wsc := &websocket.Client{
- Endpoint: "ws://" + websocketAddress,
- HandleText: func(_ *websocket.Client, frame *websocket.Frame) error {
- res = frame.Payload()
- wg.Done()
- return nil
- },
- }
-
- err = wsc.Connect()
- if err != nil {
- return nil, err
- }
-
- body, err := json.Marshal(rr.WebSocketTarget.Params)
- if err != nil {
- return nil, err
- }
-
- req := websocket.Request{
- ID: uint64(time.Now().UnixNano()),
- Method: http.MethodGet,
- Target: pathExample,
- Body: string(body),
- }
-
- reqtext, err := json.Marshal(&req)
- if err != nil {
- return nil, err
- }
-
- err = wsc.SendText(reqtext)
- if err != nil {
- return nil, err
- }
- wg.Add(1)
- wg.Wait()
-
- _ = wsc.Close()
-
- return res, nil
-}