<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <title>Test promptAuth prompts</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">
const level = Ci.nsIAuthPrompt2.LEVEL_NONE;
const authinfo = {
  username: "",
  password: "",
  domain: "",

  flags: Ci.nsIAuthInformation.AUTH_HOST,
  authenticationScheme: "basic",
  realm: "",
};

// Let prompt_common know what kind of modal type is enabled for auth prompts.
modalType = authPromptModalType;

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

  const chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
  const prompter2 = promptFac.getPrompt(chromeWin, Ci.nsIAuthPrompt2);
  prompter2.QueryInterface(Ci.nsILoginManagerAuthPrompter).browser = chromeWin.gBrowser.selectedBrowser;

  const channels = {};
  channels.channel1 = Services.io.newChannel("http://example.com",
                                             null,
                                             null,
                                             null, // aLoadingNode
                                             Services.
                                             scriptSecurityManager.getSystemPrincipal(),
                                             null, // aTriggeringPrincipal
                                             Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
                                             Ci.nsIContentPolicy.TYPE_OTHER);

  channels.channel2 = Services.io.newChannel("http://example2.com",
                                             null,
                                             null,
                                             null, // aLoadingNode
                                             Services.
                                             scriptSecurityManager.getSystemPrincipal(),
                                             null, // aTriggeringPrincipal
                                             Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
                                             Ci.nsIContentPolicy.TYPE_OTHER);

  addMessageListener("proxyPrompter", function onMessage(msg) {
    const args = [...msg.args];
    const channelName = args.shift();
    // Replace the channel name string (arg. 0) with the channel by that name.
    args.unshift(channels[channelName]);

    const rv = prompter2[msg.methodName](...args);
    return {
      rv,
      // Send the args back to content so out/inout args can be checked.
      args: msg.args,
    };
  });
});

const prompter2 = new PrompterProxy(prompterParent);

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_accept() {
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "inuser",
    passValue: "inpass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  const action = {
    buttonClick: "ok",
    textField: "outuser",
    passField: "outpass",
  };
  authinfo.username = "inuser";
  authinfo.password = "inpass";
  authinfo.realm    = "some realm";

  promptDone = handlePrompt(state, action);
  // Since prompter2 is actually a proxy to send a message to a chrome script and
  // we can't send a channel in a message, we instead send the channel name that
  // already exists in the chromeScript.
  const isOk = prompter2.promptAuth("channel1", level, authinfo);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  is(authinfo.username, "outuser", "Checking returned username");
  is(authinfo.password, "outpass", "Checking returned password");
});

add_task(async function test_cancel() {
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "outuser",
    passValue: "outpass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  const action = {
    buttonClick: "cancel",
  };
  promptDone = handlePrompt(state, action);
  const isOk = prompter2.promptAuth("channel1", level, authinfo);
  await promptDone;

  ok(!isOk, "Checking dialog return value (cancel)");
});

add_task(async function test_pwonly() {
  // test filling in password-only login
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "",
    passValue: "examplepass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  const action = {
    buttonClick: "ok",
  };
  authinfo.username = "";
  authinfo.password = "";
  authinfo.realm    = "http://example.com";

  promptDone = handlePrompt(state, action);
  const isOk = prompter2.promptAuth("channel1", level, authinfo);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  is(authinfo.username, "", "Checking returned username");
  is(authinfo.password, "examplepass", "Checking returned password");
});

add_task(async function test_multipleExisting() {
  // test filling in existing login (undetermined from multiple selection)
  // user2name/user2pass would also be valid to fill here.
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "user1name",
    passValue: "user1pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  const action = {
    buttonClick: "ok",
  };
  authinfo.username = "";
  authinfo.password = "";
  authinfo.realm    = "http://example2.com";

  promptDone = handlePrompt(state, action);
  const isOk = prompter2.promptAuth("channel2", level, authinfo);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  ok(authinfo.username == "user1name" || authinfo.username == "user2name", "Checking returned username");
  ok(authinfo.password == "user1pass" || authinfo.password == "user2pass", "Checking returned password");
});

add_task(async function test_multipleExisting2() {
  // test filling in existing login (undetermined --> user1)
  // user2name/user2pass would also be valid to fill here.
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "user1name",
    passValue: "user1pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  // enter one of the known logins, test 504+505 exercise the two possible states.
  const action = {
    buttonClick: "ok",
    textField: "user1name",
    passField: "user1pass",
  };
  authinfo.username = "";
  authinfo.password = "";
  authinfo.realm    = "http://example2.com";

  promptDone = handlePrompt(state, action);
  const isOk = prompter2.promptAuth("channel2", level, authinfo);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  is(authinfo.username, "user1name", "Checking returned username");
  is(authinfo.password, "user1pass", "Checking returned password");
});

add_task(async function test_multipleExisting3() {
  // test filling in existing login (undetermined --> user2)
  // user2name/user2pass would also be valid to fill here.
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "user1name",
    passValue: "user1pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  // enter one of the known logins, test 504+505 exercise the two possible states.
  const action = {
    buttonClick: "ok",
    textField: "user2name",
    passField: "user2pass",
  };
  authinfo.username = "";
  authinfo.password = "";
  authinfo.realm    = "http://example2.com";

  promptDone = handlePrompt(state, action);
  const isOk = prompter2.promptAuth("channel2", level, authinfo);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  is(authinfo.username, "user2name", "Checking returned username");
  is(authinfo.password, "user2pass", "Checking returned password");
});

add_task(async function test_changingMultiple() {
  // test changing a password (undetermined --> user2 w/ newpass)
  // user2name/user2pass would also be valid to fill here.
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "user1name",
    passValue: "user1pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  // force to user2, and change the password
  const action = {
    buttonClick: "ok",
    textField: "user2name",
    passField: "NEWuser2pass",
  };
  authinfo.username = "";
  authinfo.password = "";
  authinfo.realm    = "http://example2.com";

  promptDone = handlePrompt(state, action);
  const isOk = prompter2.promptAuth("channel2", level, authinfo);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  is(authinfo.username, "user2name", "Checking returned username");
  is(authinfo.password, "NEWuser2pass", "Checking returned password");
});

add_task(async function test_changingMultiple2() {
  // test changing a password (undetermined --> user2 w/ origpass)
  // user2name/user2pass would also be valid to fill here.
  const state = {
    msg: "This site is asking you to sign in.",
    title: "Authentication Required",
    textValue: "user1name",
    passValue: "user1pass",
    iconClass: "authentication-icon question-icon",
    titleHidden: true,
    textHidden: false,
    passHidden: false,
    checkHidden: true,
    checkMsg: "",
    checked: false,
    focused: "textField",
    defButton: "button0",
  };
  // force to user2, and change the password back
  const action = {
    buttonClick: "ok",
    textField: "user2name",
    passField: "user2pass",
  };
  authinfo.username = "";
  authinfo.password = "";
  authinfo.realm    = "http://example2.com";

  promptDone = handlePrompt(state, action);
  const isOk = prompter2.promptAuth("channel2", level, authinfo);
  await promptDone;

  ok(isOk, "Checking dialog return value (accept)");
  is(authinfo.username, "user2name", "Checking returned username");
  is(authinfo.password, "user2pass", "Checking returned password");
});
</script>
</pre>
</body>
</html>
