<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Test prompter.{prompt,asyncPromptPassword,asyncPromptUsernameAndPassword}</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="pwmgr_common.js"></script>
  <script type="text/javascript" src="../../../prompts/test/prompt_common.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<p id="display"></p>

<div id="content" style="display: none">
</div>

<pre id="test">
<script class="testbody" type="text/javascript">
var state, action;
var uname  = { value: null };
var pword  = { value: null };
var result = { value: null };
var isOk;

// Force parent to not look for tab-modal prompts, as they're not used for auth prompts.
modalType = Ci.nsIPrompt.MODAL_TYPE_WINDOW;

let prompterParent = runInParent(() => {
  const promptFac = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"].
                    getService(Ci.nsIPromptFactory);

  let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
  let prompter1 = promptFac.getPrompt(chromeWin, Ci.nsIAuthPrompt);

  addMessageListener("proxyPrompter", async function onMessage(msg) {
    let rv = await prompter1[msg.methodName](...msg.args);
    return {
      rv,
      // Send the args back to content so out/inout args can be checked.
      args: msg.args,
    };
  });
});

let prompter1 = new PrompterProxy(prompterParent);

const defaultTitle = "the title";
const defaultMsg = "the message";

add_setup(async () => {
    await setStoredLoginsAsync(
    ["http://example.com", null, "http://example.com", "", "examplepass", "", ""],
    ["http://example2.com", null, "http://example2.com", "user1name", "user1pass", "", ""],
    ["http://example2.com", null, "http://example2.com", "user2name", "user2pass", "", ""],
    ["http://example2.com", null, "http://example2.com", "user3.name@host", "user3pass", "", ""],
    ["http://example2.com", null, "http://example2.com", "100@beef", "user3pass", "", ""],
    ["http://example2.com", null, "http://example2.com", "100%beef", "user3pass", "", ""]
  );
});

add_task(async function test_prompt_accept() {
  state = {
    msg: "the message",
    title: "the title",
    textValue: "abc",
    passValue: "",
    iconClass: "question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: true,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    textField: "xyz",
  };
  promptDone = handlePrompt(state, action);
  isOk = prompter1.prompt(defaultTitle, defaultMsg, "http://example.com",
                          Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  is(result.value, "xyz", "Checking prompt() returned value");
});

add_task(async function test_prompt_cancel() {
  state = {
    msg: "the message",
    title: "the title",
    textValue: "abc",
    passValue: "",
    iconClass: "question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: true,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "cancel",
  };
  promptDone = handlePrompt(state, action);
  isOk = prompter1.prompt(defaultTitle, defaultMsg, "http://example.com",
                          Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, "abc", result);
  await promptDone;
  ok(!isOk, "Checking dialog return value (cancel)");
});

add_task(async function test_promptPassword_defaultAccept() {
  // Default password provided, existing logins are ignored.
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "inputpw",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: true,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "passField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    passField: "secret",
  };
  pword.value = "inputpw";
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://example.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "secret", "Checking returned password");
});

add_task(async function test_promptPassword_defaultCancel() {
  // Default password provided, existing logins are ignored.
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "inputpw",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: true,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "passField",
    defButton: "button0",
  };
  action = {
    buttonClick: "cancel",
  };
  pword.value = "inputpw";
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://example.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  await promptDone;
  ok(!isOk, "Checking dialog return value (cancel)");
});

add_task(async function test_promptPassword_emptyAccept() {
  // No default password provided, realm does not match existing login.
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: true,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "passField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    passField: "secret",
  };
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "secret", "Checking returned password");
});

add_task(async function test_promptPassword_saved() {
  // No default password provided, matching login is returned w/o prompting.
  pword.value = null;
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://example.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "examplepass", "Checking returned password");
});

add_task(async function test_promptPassword_noMatchingPasswordForEmptyUN() {
  // No default password provided, none of the logins from this host are
  // password-only so the user is prompted.
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: true,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "passField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    passField: "secret",
  };
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://example2.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "secret", "Checking returned password");
});

add_task(async function test_promptPassword_matchingPWForUN() {
  // No default password provided, matching login is returned w/o prompting.
  pword.value = null;
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://user1name@example2.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "user1pass", "Checking returned password");
});

add_task(async function test_promptPassword_matchingPWForUN2() {
  // No default password provided, matching login is returned w/o prompting.
  pword.value = null;
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://user2name@example2.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "user2pass", "Checking returned password");
});

add_task(async function test_promptPassword_matchingPWForUN3() {
  // No default password provided, matching login is returned w/o prompting.
  pword.value = null;
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://user3%2Ename%40host@example2.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "user3pass", "Checking returned password");
});

add_task(async function test_promptPassword_extraAt() {
  // No default password provided, matching login is returned w/o prompting.
  pword.value = null;
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://100@beef@example2.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "user3pass", "Checking returned password");
});

add_task(async function test_promptPassword_usernameEncoding() {
  // No default password provided, matching login is returned w/o prompting.
  pword.value = null;
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "http://100%25beef@example2.com",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "user3pass", "Checking returned password");

  // XXX test saving a password with  Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY
});

add_task(async function test_promptPassword_realm() {
  // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: true,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "passField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    passField: "fill2pass",
  };
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "fill2pass", "Checking returned password");
});

add_task(async function test_promptPassword_realm2() {
  // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: true,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "passField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    passField: "fill2pass",
  };
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                  Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(pword.value, "fill2pass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_accept() {
  state = {
    msg: "the message",
    title: "the title",
    textValue: "inuser",
    passValue: "inpass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    textField: "outuser",
    passField: "outpass",
  };
  uname.value = "inuser";
  pword.value = "inpass";
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "outuser", "Checking returned username");
  is(pword.value, "outpass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_cancel() {
  state = {
    msg: "the message",
    title: "the title",
    textValue: "inuser",
    passValue: "inpass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "cancel",
  };
  uname.value = "inuser";
  pword.value = "inpass";
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://nonexample.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
  await promptDone;
  ok(!isOk, "Checking dialog return value (cancel)");
});

add_task(async function test_promptUsernameAndPassword_autofill() {
  // test filling in existing password-only login
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "examplepass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
  };
  uname.value = null;
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://example.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "", "Checking returned username");
  is(pword.value, "examplepass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_multipleExisting() {
  // test filling in existing login (undetermined from multiple selection)
  // user2name/user2pass would also be valid to fill here.
  state = {
    msg: "the message",
    title: "the title",
    textValue: "user1name",
    passValue: "user1pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
  };
  uname.value = null;
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  ok(uname.value == "user1name" || uname.value == "user2name", "Checking returned username");
  ok(pword.value == "user1pass" || uname.value == "user2pass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_multipleExisting1() {
  // test filling in existing login (user1 from multiple selection)
  state = {
    msg: "the message",
    title: "the title",
    textValue: "user1name",
    passValue: "user1pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
  };
  uname.value = "user1name";
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "user1name", "Checking returned username");
  is(pword.value, "user1pass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_multipleExisting2() {
  // test filling in existing login (user2 from multiple selection)
  state = {
    msg: "the message",
    title: "the title",
    textValue: "user2name",
    passValue: "user2pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
  };
  uname.value = "user2name";
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "user2name", "Checking returned username");
  is(pword.value, "user2pass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_passwordChange() {
  // test changing password
  state = {
    msg: "the message",
    title: "the title",
    textValue: "user2name",
    passValue: "user2pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    passField: "NEWuser2pass",
  };
  uname.value = "user2name";
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "user2name", "Checking returned username");
  is(pword.value, "NEWuser2pass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_changePasswordBack() {
  // test changing password (back to original value)
  state = {
    msg: "the message",
    title: "the title",
    textValue: "user2name",
    passValue: "NEWuser2pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    passField: "user2pass",
  };
  uname.value = "user2name";
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "http://example2.com",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "user2name", "Checking returned username");
  is(pword.value, "user2pass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_realm() {
  // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    textField: "fill2user",
    passField: "fill2pass",
  };
  uname.value = null;
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "fill2user", "Checking returned username");
  is(pword.value, "fill2pass", "Checking returned password");
});

add_task(async function test_promptUsernameAndPassword_realm2() {
  // We don't pre-fill or save for NS_GetAuthKey-generated realms, but we should still prompt
  state = {
    msg: "the message",
    title: "the title",
    textValue: "",
    passValue: "",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  action = {
    buttonClick: "ok",
    textField: "fill2user",
    passField: "fill2pass",
  };
  uname.value = null;
  pword.value = null;
  promptDone = handlePrompt(state, action);
  isOk = await prompter1.asyncPromptUsernameAndPassword(defaultTitle, defaultMsg, "example2.com:80 (somerealm)",
                                             Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, uname, pword);
  await promptDone;
  ok(isOk, "Checking dialog return value (accept)");
  is(uname.value, "fill2user", "Checking returned username");
  is(pword.value, "fill2pass", "Checking returned password");
});

</script>
</pre>
</body>
</html>
