diff options
-rw-r--r-- | docs/using-monkey.md | 9 | ||||
-rw-r--r-- | frontends/monkey/401login.c | 3 | ||||
-rw-r--r-- | test/monkeyfarmer.py | 89 |
3 files changed, 99 insertions, 2 deletions
diff --git a/docs/using-monkey.md b/docs/using-monkey.md index f4cb9d66a..b9155746a 100644 --- a/docs/using-monkey.md +++ b/docs/using-monkey.md @@ -138,10 +138,14 @@ Commands Cause a login to proceed using the set credentials + This will send a `DESTROY` message back. + * `LOGIN DESTROY` _%id%_ Cause a login to fail + This will send a `DESTROY` message back. + Responses --------- @@ -378,6 +382,11 @@ Responses Subsequent to this message, the user of monkey is at liberty to issue `LOGIN` commands to control the response of the `401LOGIN` process. +* `LOGIN DESTROY LWIN` _%id%_ + + The given login window has been destroyed and should no longer be sent + commands otherwise undefined behaviour may ensue. + ### Plotter messages > **Note, Monkey won't clip coordinates, but sometimes the core does.** diff --git a/frontends/monkey/401login.c b/frontends/monkey/401login.c index 00913156a..b9e75bf8f 100644 --- a/frontends/monkey/401login.c +++ b/frontends/monkey/401login.c @@ -94,6 +94,7 @@ monkey_find_login_by_num(uint32_t login_num) } static void free_login_context(struct monkey401 *m401_ctx) { + moutf(MOUT_LOGIN, "DESTROY LWIN %u", m401_ctx->num); RING_REMOVE(m401_ring, m401_ctx); if (m401_ctx->username != NULL) { free(m401_ctx->username); @@ -121,7 +122,7 @@ monkey_login_handle_go(int argc, char **argv) } m401_ctx->cb(m401_ctx->username, m401_ctx->password, m401_ctx->cbpw); - + free_login_context(m401_ctx); } diff --git a/test/monkeyfarmer.py b/test/monkeyfarmer.py index 239a63e0e..b5d969e7c 100644 --- a/test/monkeyfarmer.py +++ b/test/monkeyfarmer.py @@ -125,6 +125,7 @@ class Browser: def __init__(self, monkey_cmd=["./nsmonkey"], quiet=False): self.farmer = MonkeyFarmer(monkey_cmd=monkey_cmd, online=self.on_monkey_line, quiet=quiet) self.windows = {} + self.logins = {} self.current_draw_target = None self.started = False self.stopped = False @@ -175,6 +176,19 @@ class Browser: else: win.handle(action, *args) + def handle_LOGIN(self, action, _lwin, winid, *args): + if action == "OPEN": + new_win = LoginWindow(self, winid, *args) + self.logins[winid] = new_win + else: + win = self.logins.get(winid, None) + if win is None: + print(" Unknown login window id {}".format(winid)) + else: + win.handle(action, *args) + if win.alive and win.ready: + self.handle_ready_login(win) + def handle_PLOT(self, *args): if self.current_draw_target is not None: self.current_draw_target.handle_plot(*args) @@ -189,8 +203,63 @@ class Browser: self.farmer.loop(once=True) poss_wins = set(self.windows.keys()).difference(wins_known) return self.windows[poss_wins.pop()] + + def handle_ready_login(self, lwin): + # Override this method to do useful stuff + lwin.destroy() + +class LoginWindow: + def __init__(self, browser, winid, _url, *url): + self.alive = True + self.ready = False + self.browser = browser + self.winid = winid + self.url = " ".join(url) + self.username = None + self.password = None + self.realm = None + + def handle(self, action, _str="STR", *rest): + content = " ".join(rest) + if action == "USER": + self.username = content + elif action == "PASS": + self.password = content + elif action == "REALM": + self.realm = content + elif action == "DESTROY": + self.alive = False + else: + raise AssertionError("Unknown action {} for login window".format(action)) + if not (self.username is None or self.password is None or self.realm is None): + self.ready = True + + def send_username(self, username=None): + assert(self.alive) + if username is None: + username = self.username + self.browser.farmer.tell_monkey("LOGIN USERNAME {} {}".format(self.winid, username)) + + def send_password(self, password=None): + assert(self.alive) + if password is None: + password = self.password + self.browser.farmer.tell_monkey("LOGIN PASSWORD {} {}".format(self.winid, password)) + + def _wait_dead(self): + while self.alive: + self.browser.farmer.loop(once=True) + + def go(self): + assert(self.alive) + self.browser.farmer.tell_monkey("LOGIN GO {}".format(self.winid)) + self._wait_dead() + + def destroy(self): + assert(self.alive) + self.browser.farmer.tell_monkey("LOGIN DESTROY {}".format(self.winid)) + self._wait_dead() - class BrowserWindow: def __init__(self, browser, winid, _for, coreid, _existing, otherid, _newtab, newtab, _clone, clone): self.alive = True @@ -385,6 +454,24 @@ if __name__ == '__main__': browser.quit_and_wait() + class FooBarLogin(Browser): + def handle_ready_login(self, lwin): + lwin.send_username("foo") + lwin.send_password("bar") + lwin.go() + + browser = FooBarLogin(quiet=True) + win = browser.new_window() + win.load_page("https://httpbin.org/basic-auth/foo/bar") + cmds = win.redraw() + + for cmd in cmds: + if cmd[0] == "TEXT": + x = cmd[2] + y = cmd[4] + rest = " ".join(cmd[6:]) + print("{} {} -> {}".format(x,y,rest)) + #print("Discussion was:") #for line in browser.farmer.discussion: # print("{} {}".format(line[0], line[1])) |