diff options
Diffstat (limited to 'toolkit/components/passwordmgr/test')
18 files changed, 68 insertions, 77 deletions
diff --git a/toolkit/components/passwordmgr/test/LoginTestUtils.sys.mjs b/toolkit/components/passwordmgr/test/LoginTestUtils.sys.mjs index 94e48aac6a..c16a44735e 100644 --- a/toolkit/components/passwordmgr/test/LoginTestUtils.sys.mjs +++ b/toolkit/components/passwordmgr/test/LoginTestUtils.sys.mjs @@ -67,6 +67,13 @@ export const LoginTestUtils = { return Services.logins.addLoginAsync(login); }, + /** + * Removes a login from the store + */ + async removeLogin(login) { + return Services.logins.removeLogin(login); + }, + async modifyLogin(oldLogin, newLogin) { const storageChangedPromise = TestUtils.topicObserved( "passwordmgr-storage-changed", diff --git a/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js index 0069c653a5..2115272abe 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js +++ b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_multiTab.js @@ -88,13 +88,6 @@ async function testTabAuthed(expectAuthed, { tab, loadPromise, authOptions }) { ); } -add_setup(async function () { - await SpecialPowers.pushPrefEnv({ - // This test relies on tab auth prompts. - set: [["prompts.modalType.httpAuth", Services.prompt.MODAL_TYPE_TAB]], - }); -}); - add_task(async function test() { let tabA = await openTabWithAuthPrompt(ORIGIN1, { user: "userA", diff --git a/toolkit/components/passwordmgr/test/browser/browser_basicAuth_rateLimit.js b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_rateLimit.js index b0a5b8b335..214ae5d299 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_basicAuth_rateLimit.js +++ b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_rateLimit.js @@ -5,12 +5,10 @@ // This tests that the basic auth dialog can not be used for DOS attacks // and that the protections are reset on user-initiated navigation/reload. -let promptModalType = Services.prefs.getIntPref("prompts.modalType.httpAuth"); - function promiseAuthWindowShown() { return PromptTestUtils.handleNextPrompt( window, - { modalType: promptModalType, promptType: "promptUserAndPass" }, + { modalType: Ci.nsIPrompt.MODAL_TYPE_TAB, promptType: "promptUserAndPass" }, { buttonNumClick: 1 } ); } diff --git a/toolkit/components/passwordmgr/test/browser/browser_basicAuth_switchTab.js b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_switchTab.js index 8fddea4c93..8e993388e7 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_basicAuth_switchTab.js +++ b/toolkit/components/passwordmgr/test/browser/browser_basicAuth_switchTab.js @@ -2,14 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -let modalType = Services.prefs.getIntPref("prompts.modalType.httpAuth"); - -add_task(async function test() { +add_task(async function test_auth_switchtab() { let tab = BrowserTestUtils.addTab(gBrowser); isnot(tab, gBrowser.selectedTab, "New tab shouldn't be selected"); let authPromptShown = PromptTestUtils.waitForPrompt(tab.linkedBrowser, { - modalType, + modalType: Ci.nsIPrompt.MODAL_TYPE_TAB, promptType: "promptUserAndPass", }); diff --git a/toolkit/components/passwordmgr/test/browser/browser_doorhanger_form_password_edit.js b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_form_password_edit.js index 23afd2c6ab..ad91270eb5 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_doorhanger_form_password_edit.js +++ b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_form_password_edit.js @@ -30,7 +30,7 @@ let testCases = [ doorhanger: { type: "password-save", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "", password: "abcXYZ", toggle: "visible", @@ -56,7 +56,7 @@ let testCases = [ doorhanger: { type: "password-save", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "", password: "pass-changed", toggle: "visible", @@ -80,7 +80,7 @@ let testCases = [ doorhanger: { type: "password-change", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "user1", password: "autopass-changed", }, @@ -104,7 +104,7 @@ let testCases = [ doorhanger: { type: "password-save", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "user2", password: "pass2", toggle: "visible", @@ -147,7 +147,7 @@ let testCases = [ doorhanger: { type: "password-save", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "user2", password: "pass1", toggle: "visible", @@ -174,7 +174,7 @@ let testCases = [ doorhanger: { type: "password-change", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "user-saved", password: "pass2", toggle: "visible", @@ -198,7 +198,7 @@ let testCases = [ doorhanger: { type: "password-change", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "user1", password: "pass1", toggle: "visible", @@ -244,7 +244,7 @@ let testCases = [ doorhanger: { type: "password-save", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "", password: "a", toggle: "visible", @@ -271,7 +271,7 @@ let testCases = [ doorhanger: { type: "password-save", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "", password: "abc", toggle: "visible", @@ -296,7 +296,7 @@ let testCases = [ doorhanger: { type: "password-change", dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, username: "", password: "pass", toggle: "visible", diff --git a/toolkit/components/passwordmgr/test/browser/browser_doorhanger_generated_password.js b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_generated_password.js index 798337ddda..dd3a1a216e 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_doorhanger_generated_password.js +++ b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_generated_password.js @@ -481,7 +481,7 @@ add_task(async function autocomplete_generated_password_saved_empty_username() { info("Waiting to openAndVerifyDoorhanger"); await openAndVerifyDoorhanger(browser, "password-change", { dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -493,7 +493,7 @@ add_task(async function autocomplete_generated_password_saved_empty_username() { await submitForm(browser); let notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: false, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -648,7 +648,7 @@ add_task(async function ac_gen_pw_saved_empty_un_stored_non_empty_un_in_form() { info("Waiting to openAndVerifyDoorhanger"); await openAndVerifyDoorhanger(browser, "password-save", { dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "myusername", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -660,7 +660,7 @@ add_task(async function ac_gen_pw_saved_empty_un_stored_non_empty_un_in_form() { await submitForm(browser); let notif = await openAndVerifyDoorhanger(browser, "password-save", { dismissed: false, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "myusername", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -719,7 +719,7 @@ add_task(async function contextfill_generated_password_saved_empty_username() { info("Waiting to openAndVerifyDoorhanger"); await openAndVerifyDoorhanger(browser, "password-change", { dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -731,7 +731,7 @@ add_task(async function contextfill_generated_password_saved_empty_username() { await submitForm(browser); let notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: false, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -789,7 +789,7 @@ async function autocomplete_generated_password_edited_no_auto_save( info("Waiting to openAndVerifyDoorhanger"); let notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -812,7 +812,7 @@ async function autocomplete_generated_password_edited_no_auto_save( info("Waiting to openAndVerifyDoorhanger"); notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "", passwordLength: LoginTestUtils.generation.LENGTH + 2, }); @@ -836,7 +836,7 @@ async function autocomplete_generated_password_edited_no_auto_save( await submitForm(browser); notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: false, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "", passwordLength: LoginTestUtils.generation.LENGTH + 2, }); @@ -957,7 +957,7 @@ add_task(async function contextmenu_fill_generated_password_and_set_username() { await submitForm(browser); let notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: false, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "differentuser", passwordLength: LoginTestUtils.generation.LENGTH, }); @@ -1386,7 +1386,7 @@ add_task(async function autosaved_login_updated_to_existing_login_onsubmit() { await waitForDoorhanger(browser, "password-change"); notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: false, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "user1", password: autoSavedLogin.password, }); @@ -1611,7 +1611,7 @@ add_task(async function form_change_from_autosaved_login_to_existing_login() { // the previous doorhanger would have old values, verify it was updated/replaced with new values from the form notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: true, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: user1LoginSnapshot.username, passwordLength: user1LoginSnapshot.password.length, }); @@ -1818,7 +1818,7 @@ add_task(async function form_edit_username_and_password_of_generated_login() { info("Verifying the doorhanger"); notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: true, - anchorExtraAttr: expectedConfirmation ? "attention" : "", + anchorExtraAttr: expectedConfirmation ? "attention" : null, usernameValue: expectedDoorhangerUsername, passwordLength: expectedDoorhangerPassword.length, }); @@ -1835,7 +1835,7 @@ add_task(async function form_edit_username_and_password_of_generated_login() { await passwordChangeDoorhangerPromise; notif = await openAndVerifyDoorhanger(browser, "password-change", { dismissed: false, - anchorExtraAttr: "", + anchorExtraAttr: null, usernameValue: "someuser", passwordLength: LoginTestUtils.generation.LENGTH + 2, }); diff --git a/toolkit/components/passwordmgr/test/browser/browser_entry_point_telemetry.js b/toolkit/components/passwordmgr/test/browser/browser_entry_point_telemetry.js index 9241f18612..2fbca0381b 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_entry_point_telemetry.js +++ b/toolkit/components/passwordmgr/test/browser/browser_entry_point_telemetry.js @@ -68,7 +68,7 @@ add_task(async function pageInfo_entryPoint() { }, async function (_browser) { info("pageInfo_entryPoint, opening pageinfo"); - let pageInfo = BrowserPageInfo(TEST_ORIGIN, "securityTab", {}); + let pageInfo = BrowserCommands.pageInfo(TEST_ORIGIN, "securityTab", {}); await BrowserTestUtils.waitForEvent(pageInfo, "page-info-init"); info( "pageInfo_entryPoint, got pageinfo, wait until password button is visible" diff --git a/toolkit/components/passwordmgr/test/browser/browser_private_window.js b/toolkit/components/passwordmgr/test/browser/browser_private_window.js index 31fe82cf8b..8e1e22c20f 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_private_window.js +++ b/toolkit/components/passwordmgr/test/browser/browser_private_window.js @@ -77,7 +77,7 @@ async function loadAccessRestrictedURL(browser, url, username, password) { // Wait for the auth prompt, enter the login details and close the prompt await PromptTestUtils.handleNextPrompt( browser, - { modalType: authPromptModalType, promptType: "promptUserAndPass" }, + { modalType: Ci.nsIPrompt.MODAL_TYPE_TAB, promptType: "promptUserAndPass" }, { buttonNumClick: 0, loginInput: username, passwordInput: password } ); @@ -106,13 +106,11 @@ const authUrl = `https://example.com/${DIRECTORY_PATH}authenticate.sjs`; let normalWin; let privateWin; -let authPromptModalType; // XXX: Note that tasks are currently run in sequence. Some tests may assume the state // resulting from successful or unsuccessful logins in previous tasks add_task(async function test_setup() { - authPromptModalType = Services.prefs.getIntPref("prompts.modalType.httpAuth"); normalWin = await BrowserTestUtils.openNewBrowserWindow({ private: false }); privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true }); Services.logins.removeAllUserFacingLogins(); diff --git a/toolkit/components/passwordmgr/test/browser/browser_proxyAuth_prompt.js b/toolkit/components/passwordmgr/test/browser/browser_proxyAuth_prompt.js index dfa78ff28e..6dfe7d4021 100644 --- a/toolkit/components/passwordmgr/test/browser/browser_proxyAuth_prompt.js +++ b/toolkit/components/passwordmgr/test/browser/browser_proxyAuth_prompt.js @@ -60,10 +60,6 @@ function initProxy() { } add_setup(async function () { - await SpecialPowers.pushPrefEnv({ - // This test relies on tab auth prompts. - set: [["prompts.modalType.httpAuth", Services.prompt.MODAL_TYPE_TAB]], - }); proxyChannel = await initProxy(); }); diff --git a/toolkit/components/passwordmgr/test/mochitest/pwmgr_common.js b/toolkit/components/passwordmgr/test/mochitest/pwmgr_common.js index 1494c60bbd..1e02e6a368 100644 --- a/toolkit/components/passwordmgr/test/mochitest/pwmgr_common.js +++ b/toolkit/components/passwordmgr/test/mochitest/pwmgr_common.js @@ -25,11 +25,6 @@ const { LENGTH: GENERATED_PASSWORD_LENGTH, REGEX: GENERATED_PASSWORD_REGEX } = const LOGIN_FIELD_UTILS = LoginTestUtils.loginField; const TESTS_DIR = "/tests/toolkit/components/passwordmgr/test/"; -// Depending on pref state we either show auth prompts as windows or on tab level. -let authPromptModalType = SpecialPowers.Services.prefs.getIntPref( - "prompts.modalType.httpAuth" -); - /** * Recreate a DOM tree using the outerHTML to ensure that any event listeners * and internal state for the elements are removed. @@ -1051,6 +1046,23 @@ SimpleTest.registerCleanupFunction(() => { }); }); +// This is a version of LoginHelper.loginToVanillaObject that is adapted to run +// as content JS instead of chrome JS. This is needed to make it return a +// content JS object because the structured cloning we use to send it over +// JS IPC can't deal with a cross compartment wrapper. +function loginToVanillaObject(login) { + let obj = {}; + for (let i in SpecialPowers.do_QueryInterface( + login, + SpecialPowers.Ci.nsILoginMetaInfo + )) { + if (typeof login[i] !== "function") { + obj[i] = login[i]; + } + } + return obj; +} + /** * Proxy for Services.logins (nsILoginManager). * Only supports arguments which support structured clone plus {nsILoginInfo} @@ -1067,7 +1079,7 @@ this.LoginManager = new Proxy( SpecialPowers.call_Instanceof(val, SpecialPowers.Ci.nsILoginInfo) ) { loginInfoIndices.push(index); - return LoginHelper.loginToVanillaObject(val); + return loginToVanillaObject(val); } return val; diff --git a/toolkit/components/passwordmgr/test/mochitest/test_formless_submit_form_removal.html b/toolkit/components/passwordmgr/test/mochitest/test_formless_submit_form_removal.html index b2ff2d8845..83e2f1d3c6 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_formless_submit_form_removal.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_formless_submit_form_removal.html @@ -161,7 +161,7 @@ const TESTCASES = [ }, /* XXX - Bug 1698498 : - This test case fails because when we call querySelector in LoginRecipes.jsm + This test case fails because when we call querySelector in LoginRecipes.sys.mjs after the form is removed, querySelector can't find the element. { document: `<!-- recipe field override --> diff --git a/toolkit/components/passwordmgr/test/mochitest/test_prompt_async.html b/toolkit/components/passwordmgr/test/mochitest/test_prompt_async.html index 1edbf8cf18..84f8c4aafb 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_prompt_async.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_async.html @@ -20,8 +20,8 @@ const EXAMPLE_ORG = "http://example.org/tests/toolkit/components/passwordmgr/test/mochitest/"; let mozproxyOrigin; - // Let prompt_common know what kind of modal type is enabled for auth prompts. - modalType = authPromptModalType; + // Let prompt_common know what kind of modal type is used for auth prompts. + modalType = Ci.nsIPrompt.MODAL_TYPE_TAB; // These are magically defined on the window due to the iframe IDs /* global iframe1, iframe2a, iframe2b */ diff --git a/toolkit/components/passwordmgr/test/mochitest/test_prompt_http.html b/toolkit/components/passwordmgr/test/mochitest/test_prompt_http.html index f6f6e681dc..f008950c2b 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_prompt_http.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_http.html @@ -19,8 +19,8 @@ <script class="testbody" type="text/javascript"> var iframe = document.getElementById("iframe"); -// Let prompt_common know what kind of modal type is enabled for auth prompts. -modalType = authPromptModalType; +// Let prompt_common know what kind of modal type is used for auth prompts. +modalType = Ci.nsIPrompt.MODAL_TYPE_TAB; const AUTHENTICATE_PATH = new URL("authenticate.sjs", window.location.href).pathname; diff --git a/toolkit/components/passwordmgr/test/mochitest/test_prompt_noWindow.html b/toolkit/components/passwordmgr/test/mochitest/test_prompt_noWindow.html index 19d05e47e5..0ece6f306c 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_prompt_noWindow.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_noWindow.html @@ -17,8 +17,8 @@ <pre id="test"> <script class="testbody" type="text/javascript"> -// Let prompt_common know what kind of modal type is enabled for auth prompts. -modalType = authPromptModalType; +// Let prompt_common know what kind of modal type is used for auth prompts. +modalType = Ci.nsIPrompt.MODAL_TYPE_TAB; add_setup(async () => { await setStoredLoginsAsync( diff --git a/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth.html b/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth.html index b82ea67faa..2ce85a61a9 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth.html @@ -27,8 +27,8 @@ const authinfo = { realm: "", }; -// Let prompt_common know what kind of modal type is enabled for auth prompts. -modalType = authPromptModalType; +// Let prompt_common know what kind of modal type is used for auth prompts. +modalType = Ci.nsIPrompt.MODAL_TYPE_TAB; const prompterParent = runInParent(() => { const promptFac = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"]. diff --git a/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth_proxy.html b/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth_proxy.html index 75342cd4cb..e5e77d0bcc 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth_proxy.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_prompt_promptAuth_proxy.html @@ -31,8 +31,8 @@ let proxyAuthinfo = { realm: "", }; -// Let prompt_common know what kind of modal type is enabled for auth prompts. -modalType = authPromptModalType; +// Let prompt_common know what kind of modal type is used for auth prompts. +modalType = Ci.nsIPrompt.MODAL_TYPE_TAB; let chromeScript = runInParent(() => { const promptFac = Cc[ diff --git a/toolkit/components/passwordmgr/test/mochitest/test_xhr.html b/toolkit/components/passwordmgr/test/mochitest/test_xhr.html index 4461195359..b481099314 100644 --- a/toolkit/components/passwordmgr/test/mochitest/test_xhr.html +++ b/toolkit/components/passwordmgr/test/mochitest/test_xhr.html @@ -40,8 +40,8 @@ function xhrLoad(xmlDoc) { return {username, password, authok}; } -// Let prompt_common know what kind of modal type is enabled for auth prompts. -modalType = authPromptModalType; +// Let prompt_common know what kind of modal type is used for auth prompts. +modalType = Ci.nsIPrompt.MODAL_TYPE_TAB; let prompterParent = runInParent(() => { const promptFac = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"]. @@ -120,17 +120,6 @@ add_task(async function test2() { defButton: "button0", }; - // For window prompts check that the dialog is modal, chrome and dependent; - // We can't just check window.opener because that'll be - // a content window, which therefore isn't exposed (it'll lie and - // be null). - if (authPromptModalType === SpecialPowers.Services.prompt.MODAL_TYPE_WINDOW) { - state.chrome = true; - state.dialog = true; - state.chromeDependent = true; - state.isWindowModal = true; - } - let action = { buttonClick: "ok", }; diff --git a/toolkit/components/passwordmgr/test/unit/test_PasswordRulesManager_generatePassword.js b/toolkit/components/passwordmgr/test/unit/test_PasswordRulesManager_generatePassword.js index 88520769cf..43717f36c5 100644 --- a/toolkit/components/passwordmgr/test/unit/test_PasswordRulesManager_generatePassword.js +++ b/toolkit/components/passwordmgr/test/unit/test_PasswordRulesManager_generatePassword.js @@ -238,7 +238,7 @@ add_task( const TEST_BASE_ORIGIN = "example.com"; const REQUIRED_ARBITRARY_CHARACTERS = "!#$@*()_+="; // We use an extremely long password to ensure there are no invalid characters generated in the password. - // This ensures we exhaust all of "allRequiredCharacters" in PasswordGenerator.jsm. + // This ensures we exhaust all of "allRequiredCharacters" in PasswordGenerator.sys.mjs. // Otherwise, there's a small chance a "," may have been added to "allRequiredCharacters" // which will generate an invalid password in this case. const TEST_RULES = `required: [${REQUIRED_ARBITRARY_CHARACTERS}], upper, lower; maxlength: 255; minlength: 255;`; |