diff options
| author | Shulhan <ms@kilabit.info> | 2021-03-21 22:23:27 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2021-03-21 22:26:05 +0700 |
| commit | 360bf84d2af244c7926c2aa7c1f23d0c280b8238 (patch) | |
| tree | 2bcf39d2c6425980abdfe4a310f31eaf0f11b9a1 | |
| parent | 5828835bcd18eff070789fd82401480c244bbc27 (diff) | |
| download | gorankusu-360bf84d2af244c7926c2aa7c1f23d0c280b8238.tar.xz | |
all: implement interface and API to delete attack result
When user clicking the "Delete" button on attack result item, it will
send request to API to delete the selected item. Server will check
if the requested result file name exist and delete them from file system
if its exist, otherwise it will return 404 Not found.
| -rw-r--r-- | _www/index.css | 27 | ||||
| -rw-r--r-- | _www/index.html | 3 | ||||
| -rw-r--r-- | _www/index.js | 124 | ||||
| -rw-r--r-- | http_target.go | 7 | ||||
| -rw-r--r-- | trunks.go | 79 |
5 files changed, 182 insertions, 58 deletions
diff --git a/_www/index.css b/_www/index.css index ef43f5b..f80f449 100644 --- a/_www/index.css +++ b/_www/index.css @@ -3,6 +3,28 @@ body { margin: 0; padding: 0; } + +#notif, +#notif-error { + position: absolute; + top: 1em; + left: 10%; + width: 80%; +} + +#notif > div { + background-color: white; + border: 1px solid lightgrey; + margin: 1em auto; + padding: 1em; +} + +#notif-error > div { + background-color: salmon; + margin: 1em auto; + padding: 1em; +} + .nav { height: calc(100% - 2em); padding: 1em; @@ -41,8 +63,11 @@ body { } .mono { background-color: cornsilk; - border-radius: 1em; font-family: monospace; padding: 1em; overflow: auto; } + +.results > .result-name { + margin-bottom: 1em; +} diff --git a/_www/index.html b/_www/index.html index 97ac64d..56754af 100644 --- a/_www/index.html +++ b/_www/index.html @@ -26,5 +26,8 @@ <div class="main"> <div id="main-content"></div> </div> + + <div id="notif"></div> + <div id="notif-error"></div> </body> </html> diff --git a/_www/index.js b/_www/index.js index 642a7bc..044bd57 100644 --- a/_www/index.js +++ b/_www/index.js @@ -127,7 +127,7 @@ function renderTarget(targetID) { let http = target.HttpTargets[x] w += ` - <div> + <div id="${http.ID}" class="HttpTarget"> <h3> ${http.Name} <button onclick="run('${target.ID}', '${http.ID}')"> @@ -137,42 +137,49 @@ function renderTarget(targetID) { Attack </button> </h3> - <div class="mono"> + + <div id="${http.ID}_preview" class="preview mono"> ${_requestMethods[http.Method]} ${http.Path} <br/> Content-Type: ${_requestTypes[http.RequestType]} </div> + + <h4>Headers</h4> + <div id="${http.ID}_headers" class="headers"></div> + + <h4>Parameters</h4> + <div id="${http.ID}_params" class="params"></div> + + <h4>Run response</h4> + <pre id="${http.ID}_response" class="response mono"></pre> + + <h4>Attack results</h4> + <div id="${http.ID}_results" class="results"></div> + </div> ` + } + w += "</div>" + + document.getElementById("main-content").innerHTML = w + + for (let x = 0; x < target.HttpTargets.length; x++) { + let http = target.HttpTargets[x] if (Object.keys(http.Headers).length > 0) { - w += "<h4>Headers</h4>" - w += renderHttpTargetHeaders(target, http) + renderHttpTargetHeaders(target, http) } if (Object.keys(http.Params).length > 0) { - w += "<h4>Parameters</h4>" - w += renderHttpTargetParams(target, http) + renderHttpTargetParams(target, http) } - w += ` - <h4>Run response</h4> - <pre id="${http.ID}_response" class="mono"> - </pre> - ` - if (http.Results && Object.keys(http.Results).length > 0) { - w += "<h4>Attack results</h4>" - w += renderHttpAttackResults(target, http) + renderHttpAttackResults(target, http) } - - w += "</div>" } - w += "</div>" - - document.getElementById("main-content").innerHTML = w } function renderHttpTargetHeaders(target, http) { - let w = `<div id="${http.ID}_headers">` + let w = "" for (const k in http.Headers) { w += ` <div class="input"> @@ -184,12 +191,11 @@ function renderHttpTargetHeaders(target, http) { </div> ` } - w += "</div>" - return w + document.getElementById(`${http.ID}_headers`).innerHTML = w } function renderHttpTargetParams(target, http) { - let w = `<div id="${http.ID}_params">` + let w = "" for (const k in http.Params) { w += ` <div class="input"> @@ -201,30 +207,33 @@ function renderHttpTargetParams(target, http) { </div> ` } - w += "</div>" - return w + document.getElementById(`${http.ID}_params`).innerHTML = w } function renderHttpAttackResults(target, http) { - let w = `<div id="${http.ID}_results">` + let w = "" for (let x = 0; x < http.Results.length; x++) { let result = http.Results[x] w += ` - <div> - <button onclick="getAttackResult(this, '${result.Name}')"> + <div class="result-name"> + <button onclick="attackResultGet(this, '${result.Name}')"> Show </button> -- ${result.Name} + + <button onclick="attackResultDelete('${result.Name}')"> + Delete + </button> + </div> <div class="result" id="${result.Name}" style="display: none;"> </div> ` } - w += "</div>" - return w + document.getElementById(`${http.ID}_results`).innerHTML = w } async function run(targetID, httpTargetID) { @@ -273,7 +282,38 @@ async function attack(targetID, httpTargetID) { let res = await fres.json() } -async function getAttackResult(button, name) { +async function attackResultDelete(name) { + let url = "/_trunks/api/target/attack/result?name=" + name + let fres = await fetch(url, { + method: "DELETE", + }) + let res = await fres.json() + if (res.code != 200) { + console.log("attackResultDelete: ", res) + notifError(res.message) + return + } + + let ids = name.split(".") + let target = _targets[ids[0]] + if (!target) { + return + } + let httpTarget = getHttpTargetByID(target, ids[1]) + if (!httpTarget) { + return + } + for (let x = 0; x < httpTarget.Results.length; x++) { + let result = httpTarget.Results[x] + if (result.Name == name) { + httpTarget.Results.splice(x, 1) + renderHttpAttackResults(target, httpTarget) + return + } + } +} + +async function attackResultGet(button, name) { let el = document.getElementById(name) if (el.style.display === "block") { @@ -320,3 +360,25 @@ function onChangeHttpParam(targetID, httpTargetID, key, val) { let httpTarget = getHttpTargetByID(target, httpTargetID) httpTarget.Params[key] = val } + +function notif(msg) { + let root = document.getElementById("notif") + let item = document.createElement("div"); + item.innerHTML = msg + root.appendChild(item) + + setTimeout(function() { + root.removeChild(item) + }, 5000) +} + +function notifError(msg) { + let root = document.getElementById("notif-error") + let item = document.createElement("div"); + item.innerHTML = msg + root.appendChild(item) + + setTimeout(function() { + root.removeChild(item) + }, 5000) +} diff --git a/http_target.go b/http_target.go index 03c05b1..5652df3 100644 --- a/http_target.go +++ b/http_target.go @@ -5,10 +5,12 @@ package trunks import ( + "os" "path/filepath" "sync" libhttp "github.com/shuLhan/share/lib/http" + "github.com/shuLhan/share/lib/mlog" vegeta "github.com/tsenart/vegeta/v12/lib" ) @@ -87,6 +89,11 @@ func (ht *HttpTarget) deleteResult(result *AttackResult) { copy(ht.Results[x:], ht.Results[x+1:]) ht.Results[len(ht.Results)-1] = nil ht.Results = ht.Results[:len(ht.Results)-1] + + err := os.Remove(result.fullpath) + if err != nil { + mlog.Errf("deleteResult: %q: %s\n", result.fullpath, err) + } } func (ht *HttpTarget) addResult(dir, name string) (err error) { @@ -200,7 +200,7 @@ func (trunks *Trunks) registerHttpApis() (err error) { Path: apiTargetAttackResult, RequestType: libhttp.RequestTypeJSON, ResponseType: libhttp.ResponseTypeJSON, - Call: trunks.apiTargetAttackResultsDelete, + Call: trunks.apiTargetAttackResultDelete, }) if err != nil { return err @@ -302,32 +302,14 @@ func (trunks *Trunks) apiTargetAttackCancel(epr *libhttp.EndpointRequest) (resbo } func (trunks *Trunks) apiTargetAttackResultGet(epr *libhttp.EndpointRequest) (resbody []byte, err error) { - res := &libhttp.EndpointResponse{ - E: liberrors.E{ - Code: http.StatusNotFound, - Name: "ERR_ATTACK_RESULT_NOT_FOUND", - }, - } - name := epr.HttpRequest.Form.Get(paramNameName) if len(name) == 0 { return nil, errInvalidParameter(paramNameName, name) } - t, ht := trunks.getTargetByResultFilename(name) - if t == nil { - res.Message = "Target ID not found" - return nil, res - } - if ht == nil { - res.Message = "HttpTarget ID not found" - return nil, res - } - - result := ht.getResultByName(name) - if result == nil { - res.Message = "Result file not found" - return nil, res + _, _, result, err := trunks.getAttackResultByName(name) + if err != nil { + return nil, err } err = result.load() @@ -335,15 +317,33 @@ func (trunks *Trunks) apiTargetAttackResultGet(epr *libhttp.EndpointRequest) (re return nil, err } + res := libhttp.EndpointResponse{} res.Code = http.StatusOK - res.Name = "OK_TARGET_ATTACK_RESULT" + res.Name = "OK_TARGET_ATTACK_RESULT_GET" res.Data = result - return json.Marshal(res) + return json.Marshal(&res) } -func (trunks *Trunks) apiTargetAttackResultsDelete(epr *libhttp.EndpointRequest) (resbody []byte, err error) { - return resbody, nil +func (trunks *Trunks) apiTargetAttackResultDelete(epr *libhttp.EndpointRequest) (resbody []byte, err error) { + name := epr.HttpRequest.Form.Get(paramNameName) + if len(name) == 0 { + return nil, errInvalidParameter(paramNameName, name) + } + + _, ht, result, err := trunks.getAttackResultByName(name) + if err != nil { + return nil, err + } + + ht.deleteResult(result) + + res := libhttp.EndpointResponse{} + res.Code = http.StatusOK + res.Name = "OK_TARGET_ATTACK_RESULT_GET" + res.Data = result + + return json.Marshal(&res) } func (trunks *Trunks) apiTargetRun(epr *libhttp.EndpointRequest) ([]byte, error) { @@ -391,6 +391,33 @@ func (trunks *Trunks) getTargetByID(id string) *Target { return nil } +func (trunks *Trunks) getAttackResultByName(name string) (t *Target, ht *HttpTarget, result *AttackResult, err error) { + res := &libhttp.EndpointResponse{ + E: liberrors.E{ + Code: http.StatusNotFound, + Name: "ERR_ATTACK_RESULT_NOT_FOUND", + }, + } + + t, ht = trunks.getTargetByResultFilename(name) + if t == nil { + res.Message = "Target ID not found" + return nil, nil, nil, res + } + if ht == nil { + res.Message = "HttpTarget ID not found" + return nil, nil, nil, res + } + + result = ht.getResultByName(name) + if result == nil { + res.Message = "Result file not found" + return nil, nil, nil, res + } + + return t, ht, result, nil +} + func (trunks *Trunks) getTargetByResultFilename(name string) (t *Target, ht *HttpTarget) { names := strings.Split(name, ".") |
