implement password resets
This commit is contained in:
parent
29fcfbcc7c
commit
837a34d8cc
|
|
@ -299,6 +299,6 @@ div[data-cvm-node=vm0b0t] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#accountDropdownMenuLink, #accountModalError {
|
#accountDropdownMenuLink, #accountModalError, #accountModalSuccess {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -109,6 +109,10 @@
|
||||||
<span id="accountModalErrorText"></span>
|
<span id="accountModalErrorText"></span>
|
||||||
<button type="button" class="btn-close" aria-label="Close" id="accountModalErrorDismiss"></button>
|
<button type="button" class="btn-close" aria-label="Close" id="accountModalErrorDismiss"></button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="alert alert-success alert-dismissible" id="accountModalSuccess" role="alert">
|
||||||
|
<span id="accountModalSuccessText"></span>
|
||||||
|
<button type="button" class="btn-close" aria-label="Close" id="accountModalSuccessDismiss"></button>
|
||||||
|
</div>
|
||||||
<div id="accountLoginSection">
|
<div id="accountLoginSection">
|
||||||
<form id="accountLoginForm">
|
<form id="accountLoginForm">
|
||||||
<label for="accountLoginUsername">Username</label><br/>
|
<label for="accountLoginUsername">Username</label><br/>
|
||||||
|
|
@ -116,7 +120,7 @@
|
||||||
<label for="accountLoginPassword">Password</label><br/>
|
<label for="accountLoginPassword">Password</label><br/>
|
||||||
<input id="accountLoginPassword" type="password" class="form-control" placeholder="Password" name="password" required><br>
|
<input id="accountLoginPassword" type="password" class="form-control" placeholder="Password" name="password" required><br>
|
||||||
<div id="accountLoginCaptcha"></div>
|
<div id="accountLoginCaptcha"></div>
|
||||||
<button type="submit" class="btn btn-primary">Login</button>
|
<button type="submit" class="btn btn-primary">Login</button> <button type="button" class="btn btn-secondary" id="accountForgotPasswordButton">Forgot Password</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id="accountRegisterSection">
|
<div id="accountRegisterSection">
|
||||||
|
|
@ -141,7 +145,7 @@
|
||||||
<p id="accountVerifyEmailText"></p>
|
<p id="accountVerifyEmailText"></p>
|
||||||
<form id="accountVerifyEmailForm">
|
<form id="accountVerifyEmailForm">
|
||||||
<label for="accountVerifyEmailCode">Code</label><br>
|
<label for="accountVerifyEmailCode">Code</label><br>
|
||||||
<input id="accountVerifyEmailCode" type="text" class="form-control" name="code" required><br>
|
<input id="accountVerifyEmailCode" type="text" class="form-control" name="code" placeholder="Code" required><br>
|
||||||
<label for="accountVerifyEmailPassword">Your password</label><br>
|
<label for="accountVerifyEmailPassword">Your password</label><br>
|
||||||
<input id="accountVerifyEmailPassword" type="password" class="form-control" placeholder="Password" name="password" required/><br/>
|
<input id="accountVerifyEmailPassword" type="password" class="form-control" placeholder="Password" name="password" required/><br/>
|
||||||
<button type="submit" class="btn btn-primary">Verify</button>
|
<button type="submit" class="btn btn-primary">Verify</button>
|
||||||
|
|
@ -162,6 +166,30 @@
|
||||||
<input id="accountSettingsCurrentPassword" type="password" class="form-control" placeholder="Current Password" name="currentpassword" required/><br/>
|
<input id="accountSettingsCurrentPassword" type="password" class="form-control" placeholder="Current Password" name="currentpassword" required/><br/>
|
||||||
<button type="submit" class="btn btn-primary">Update</button>
|
<button type="submit" class="btn btn-primary">Update</button>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="accountResetPasswordSection">
|
||||||
|
<form id="accountResetPasswordForm">
|
||||||
|
<label for="accountResetPasswordEmail">E-Mail</label><br>
|
||||||
|
<input id="accountResetPasswordEmail" type="email" class="form-control" placeholder="E-Mail" name="email" required/><br/>
|
||||||
|
<label for="accountResetPasswordUsername">Username</label>
|
||||||
|
<input id="accountResetPasswordUsername" type="text" class="form-control" placeholder="Username" name="username" required/><br/>
|
||||||
|
<div id="accountResetPasswordCaptcha"></div>
|
||||||
|
<button type="submit" class="btn btn-primary">Reset</button>
|
||||||
|
</div>
|
||||||
|
<div id="accountResetPasswordVerifySection">
|
||||||
|
<center>
|
||||||
|
<i class="fa-solid fa-envelope" style="font-size: 12rem"></i>
|
||||||
|
<p id="accountVerifyPasswordResetText"></p>
|
||||||
|
<form id="accountResetPasswordVerifyForm">
|
||||||
|
<label for="accountResetPasswordCode">Code</label><br>
|
||||||
|
<input id="accountResetPasswordCode" type="text" class="form-control" name="code" placeholder="Code" required><br>
|
||||||
|
<label for="accountResetPasswordNewPassword">New Password</label><br>
|
||||||
|
<input id="accountResetPasswordNewPassword" type="password" class="form-control" placeholder="New Password" name="password" required/><br/>
|
||||||
|
<label for="accountResetPasswordConfirmNewPassword">Confirm New Password</label><br>
|
||||||
|
<input id="accountResetPasswordConfirmNewPassword" type="password" class="form-control" placeholder="Confirm New Password" name="confirmpassword" required/><br/>
|
||||||
|
<button type="submit" class="btn btn-primary">Reset</button>
|
||||||
|
</form>
|
||||||
|
</center>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,43 @@ export default class AuthManager {
|
||||||
res(json);
|
res(json);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendPasswordResetEmail(username : string, email : string, captchaToken : string | undefined) {
|
||||||
|
return new Promise<PasswordResetResult>(async res => {
|
||||||
|
if (!this.info) throw new Error("Cannot send password reset email without fetching API information.");
|
||||||
|
if (!captchaToken && this.info.hcaptcha.required) throw new Error("This API requires a valid hCaptcha token.");
|
||||||
|
var data = await fetch(this.apiEndpoint + "/api/v1/sendreset", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
email: email,
|
||||||
|
captchaToken: captchaToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
res(await data.json() as PasswordResetResult);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPassword(username : string, email : string, code : string, newPassword : string) {
|
||||||
|
return new Promise<PasswordResetResult>(async res => {
|
||||||
|
var data = await fetch(this.apiEndpoint + "/api/v1/reset", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
email: email,
|
||||||
|
code: code,
|
||||||
|
newPassword: newPassword
|
||||||
|
})
|
||||||
|
});
|
||||||
|
res(await data.json() as PasswordResetResult);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthServerInformation {
|
export interface AuthServerInformation {
|
||||||
|
|
@ -211,4 +248,9 @@ export interface UpdateAccountResult {
|
||||||
error : string | undefined;
|
error : string | undefined;
|
||||||
verificationRequired : boolean | undefined;
|
verificationRequired : boolean | undefined;
|
||||||
sessionExpired : boolean | undefined;
|
sessionExpired : boolean | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PasswordResetResult {
|
||||||
|
success : boolean;
|
||||||
|
error : string | undefined;
|
||||||
}
|
}
|
||||||
|
|
@ -49,8 +49,11 @@ export enum I18nStringKey {
|
||||||
kAccountModal_Register = 'kAccountModal_Register',
|
kAccountModal_Register = 'kAccountModal_Register',
|
||||||
kAccountModal_Verify = 'kAccountModal_Verify',
|
kAccountModal_Verify = 'kAccountModal_Verify',
|
||||||
kAccountModal_AccountSettings = 'kAccountModal_AccountSettings',
|
kAccountModal_AccountSettings = 'kAccountModal_AccountSettings',
|
||||||
|
kAccountModal_ResetPassword = 'kAccountModal_ResetPassword',
|
||||||
|
|
||||||
kAccountModal_VerifyText = 'kAccountModal_VerifyText',
|
kAccountModal_VerifyText = 'kAccountModal_VerifyText',
|
||||||
|
kAccountModal_VerifyPasswordResetText = 'kAccountModal_VerifyPasswordResetText',
|
||||||
|
kAccountModal_PasswordResetSuccess = 'kAccountModal_PasswordResetSuccess',
|
||||||
kMissingCaptcha = 'kMissingCaptcha',
|
kMissingCaptcha = 'kMissingCaptcha',
|
||||||
kPasswordsMustMatch = 'kPasswordsMustMatch',
|
kPasswordsMustMatch = 'kPasswordsMustMatch',
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,9 @@ const elements = {
|
||||||
accountModalError: document.getElementById("accountModalError") as HTMLDivElement,
|
accountModalError: document.getElementById("accountModalError") as HTMLDivElement,
|
||||||
accountModalErrorText: document.getElementById("accountModalErrorText") as HTMLSpanElement,
|
accountModalErrorText: document.getElementById("accountModalErrorText") as HTMLSpanElement,
|
||||||
accountModalErrorDismiss: document.getElementById("accountModalErrorDismiss") as HTMLButtonElement,
|
accountModalErrorDismiss: document.getElementById("accountModalErrorDismiss") as HTMLButtonElement,
|
||||||
|
accountModalSuccess: document.getElementById("accountModalSuccess") as HTMLDivElement,
|
||||||
|
accountModalSuccessText: document.getElementById("accountModalSuccessText") as HTMLSpanElement,
|
||||||
|
accountModalSuccessDismiss: document.getElementById("accountModalSuccessDismiss") as HTMLButtonElement,
|
||||||
accountLoginSection: document.getElementById("accountLoginSection") as HTMLDivElement,
|
accountLoginSection: document.getElementById("accountLoginSection") as HTMLDivElement,
|
||||||
accountRegisterSection: document.getElementById("accountRegisterSection") as HTMLDivElement,
|
accountRegisterSection: document.getElementById("accountRegisterSection") as HTMLDivElement,
|
||||||
accountVerifyEmailSection: document.getElementById("accountVerifyEmailSection") as HTMLDivElement,
|
accountVerifyEmailSection: document.getElementById("accountVerifyEmailSection") as HTMLDivElement,
|
||||||
|
|
@ -107,6 +110,20 @@ const elements = {
|
||||||
accountSettingsNewPassword: document.getElementById("accountSettingsNewPassword") as HTMLInputElement,
|
accountSettingsNewPassword: document.getElementById("accountSettingsNewPassword") as HTMLInputElement,
|
||||||
accountSettingsConfirmNewPassword: document.getElementById("accountSettingsConfirmNewPassword") as HTMLInputElement,
|
accountSettingsConfirmNewPassword: document.getElementById("accountSettingsConfirmNewPassword") as HTMLInputElement,
|
||||||
accountSettingsCurrentPassword: document.getElementById("accountSettingsCurrentPassword") as HTMLInputElement,
|
accountSettingsCurrentPassword: document.getElementById("accountSettingsCurrentPassword") as HTMLInputElement,
|
||||||
|
|
||||||
|
accountResetPasswordSection: document.getElementById("accountResetPasswordSection") as HTMLDivElement,
|
||||||
|
accountResetPasswordForm: document.getElementById("accountResetPasswordForm") as HTMLFormElement,
|
||||||
|
accountResetPasswordEmail: document.getElementById("accountResetPasswordEmail") as HTMLInputElement,
|
||||||
|
accountResetPasswordUsername: document.getElementById("accountResetPasswordUsername") as HTMLInputElement,
|
||||||
|
accountResetPasswordCaptcha: document.getElementById("accountResetPasswordCaptcha") as HTMLDivElement,
|
||||||
|
|
||||||
|
accountResetPasswordVerifySection: document.getElementById("accountResetPasswordVerifySection") as HTMLDivElement,
|
||||||
|
accountVerifyPasswordResetText: document.getElementById("accountVerifyPasswordResetText") as HTMLParagraphElement,
|
||||||
|
accountResetPasswordVerifyForm: document.getElementById("accountResetPasswordVerifyForm") as HTMLFormElement,
|
||||||
|
accountResetPasswordCode: document.getElementById("accountResetPasswordCode") as HTMLInputElement,
|
||||||
|
accountResetPasswordNewPassword: document.getElementById("accountResetPasswordNewPassword") as HTMLInputElement,
|
||||||
|
accountResetPasswordConfirmNewPassword: document.getElementById("accountResetPasswordConfirmNewPassword") as HTMLInputElement,
|
||||||
|
accountForgotPasswordButton: document.getElementById("accountForgotPasswordButton") as HTMLButtonElement,
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth : AuthManager|null = null;
|
let auth : AuthManager|null = null;
|
||||||
|
|
@ -879,10 +896,12 @@ async function renderAuth() {
|
||||||
elements.accountLogoutButton.style.display = "none";
|
elements.accountLogoutButton.style.display = "none";
|
||||||
elements.accountRegisterCaptcha.innerHTML = "";
|
elements.accountRegisterCaptcha.innerHTML = "";
|
||||||
elements.accountLoginCaptcha.innerHTML = "";
|
elements.accountLoginCaptcha.innerHTML = "";
|
||||||
|
elements.accountResetPasswordCaptcha.innerHTML = "";
|
||||||
if (auth!.info!.hcaptcha.required) {
|
if (auth!.info!.hcaptcha.required) {
|
||||||
var hconfig = {sitekey: auth!.info!.hcaptcha.siteKey!};
|
var hconfig = {sitekey: auth!.info!.hcaptcha.siteKey!};
|
||||||
hcaptcha.render(elements.accountRegisterCaptcha, hconfig);
|
hcaptcha.render(elements.accountRegisterCaptcha, hconfig);
|
||||||
hcaptcha.render(elements.accountLoginCaptcha, hconfig);
|
hcaptcha.render(elements.accountLoginCaptcha, hconfig);
|
||||||
|
hcaptcha.render(elements.accountResetPasswordCaptcha, hconfig);
|
||||||
}
|
}
|
||||||
var token = localStorage.getItem("collabvm_session_" + new URL(auth!.apiEndpoint).host);
|
var token = localStorage.getItem("collabvm_session_" + new URL(auth!.apiEndpoint).host);
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|
@ -905,12 +924,15 @@ function loadAccount() {
|
||||||
}
|
}
|
||||||
const accountModal = new bootstrap.Modal(elements.accountModal);
|
const accountModal = new bootstrap.Modal(elements.accountModal);
|
||||||
elements.accountModalErrorDismiss.addEventListener('click', () => elements.accountModalError.style.display = "none");
|
elements.accountModalErrorDismiss.addEventListener('click', () => elements.accountModalError.style.display = "none");
|
||||||
|
elements.accountModalSuccessDismiss.addEventListener('click', () => elements.accountModalSuccess.style.display = "none");
|
||||||
elements.accountLoginButton.addEventListener("click", () => {
|
elements.accountLoginButton.addEventListener("click", () => {
|
||||||
elements.accountModalTitle.innerText = TheI18n.GetString(I18nStringKey.kAccountModal_Login);
|
elements.accountModalTitle.innerText = TheI18n.GetString(I18nStringKey.kAccountModal_Login);
|
||||||
elements.accountRegisterSection.style.display = "none";
|
elements.accountRegisterSection.style.display = "none";
|
||||||
elements.accountVerifyEmailSection.style.display = "none";
|
elements.accountVerifyEmailSection.style.display = "none";
|
||||||
elements.accountLoginSection.style.display = "block";
|
elements.accountLoginSection.style.display = "block";
|
||||||
elements.accountSettingsSection.style.display = "none";
|
elements.accountSettingsSection.style.display = "none";
|
||||||
|
elements.accountResetPasswordSection.style.display = "none";
|
||||||
|
elements.accountResetPasswordVerifySection.style.display = "none";
|
||||||
accountModal.show();
|
accountModal.show();
|
||||||
});
|
});
|
||||||
elements.accountRegisterButton.addEventListener("click", () => {
|
elements.accountRegisterButton.addEventListener("click", () => {
|
||||||
|
|
@ -919,6 +941,8 @@ elements.accountRegisterButton.addEventListener("click", () => {
|
||||||
elements.accountVerifyEmailSection.style.display = "none";
|
elements.accountVerifyEmailSection.style.display = "none";
|
||||||
elements.accountLoginSection.style.display = "none";
|
elements.accountLoginSection.style.display = "none";
|
||||||
elements.accountSettingsSection.style.display = "none";
|
elements.accountSettingsSection.style.display = "none";
|
||||||
|
elements.accountResetPasswordSection.style.display = "none";
|
||||||
|
elements.accountResetPasswordVerifySection.style.display = "none";
|
||||||
accountModal.show();
|
accountModal.show();
|
||||||
});
|
});
|
||||||
elements.accountSettingsButton.addEventListener("click", () => {
|
elements.accountSettingsButton.addEventListener("click", () => {
|
||||||
|
|
@ -927,6 +951,8 @@ elements.accountSettingsButton.addEventListener("click", () => {
|
||||||
elements.accountVerifyEmailSection.style.display = "none";
|
elements.accountVerifyEmailSection.style.display = "none";
|
||||||
elements.accountLoginSection.style.display = "none";
|
elements.accountLoginSection.style.display = "none";
|
||||||
elements.accountSettingsSection.style.display = "block";
|
elements.accountSettingsSection.style.display = "block";
|
||||||
|
elements.accountResetPasswordSection.style.display = "none";
|
||||||
|
elements.accountResetPasswordVerifySection.style.display = "none";
|
||||||
// Fill fields
|
// Fill fields
|
||||||
elements.accountSettingsUsername.value = auth!.account!.username;
|
elements.accountSettingsUsername.value = auth!.account!.username;
|
||||||
elements.accountSettingsEmail.value = auth!.account!.email;
|
elements.accountSettingsEmail.value = auth!.account!.email;
|
||||||
|
|
@ -939,6 +965,11 @@ elements.accountLogoutButton.addEventListener('click', async () => {
|
||||||
if (VM) closeVM();
|
if (VM) closeVM();
|
||||||
renderAuth();
|
renderAuth();
|
||||||
});
|
});
|
||||||
|
elements.accountForgotPasswordButton.addEventListener('click', () => {
|
||||||
|
elements.accountModalTitle.innerText = TheI18n.GetString(I18nStringKey.kAccountModal_ResetPassword);
|
||||||
|
elements.accountLoginSection.style.display = "none";
|
||||||
|
elements.accountResetPasswordSection.style.display = "block";
|
||||||
|
});
|
||||||
// i dont know if theres a better place to put this
|
// i dont know if theres a better place to put this
|
||||||
let accountBeingVerified;
|
let accountBeingVerified;
|
||||||
elements.accountLoginForm.addEventListener('submit', async (e) => {
|
elements.accountLoginForm.addEventListener('submit', async (e) => {
|
||||||
|
|
@ -1084,6 +1115,65 @@ elements.accountSettingsForm.addEventListener('submit', async e => {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
let resetPasswordUsername;
|
||||||
|
let resetPasswordEmail;
|
||||||
|
elements.accountResetPasswordForm.addEventListener('submit', async e => {
|
||||||
|
e.preventDefault();
|
||||||
|
var hcaptchaToken = undefined;
|
||||||
|
var hcaptchaID = undefined;
|
||||||
|
if (auth!.info!.hcaptcha.required) {
|
||||||
|
hcaptchaID = elements.accountResetPasswordCaptcha.children[0].getAttribute("data-hcaptcha-widget-id")!
|
||||||
|
var response = hcaptcha.getResponse(hcaptchaID);
|
||||||
|
if (response === "") {
|
||||||
|
elements.accountModalErrorText.innerHTML = TheI18n.GetString(I18nStringKey.kMissingCaptcha);
|
||||||
|
elements.accountModalError.style.display = "block";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
hcaptchaToken = response;
|
||||||
|
}
|
||||||
|
var username = elements.accountResetPasswordUsername.value;
|
||||||
|
var email = elements.accountResetPasswordEmail.value;
|
||||||
|
var result = await auth!.sendPasswordResetEmail(username, email, hcaptchaToken);
|
||||||
|
if (auth!.info!.hcaptcha.required) hcaptcha.reset(hcaptchaID);
|
||||||
|
if (result.success) {
|
||||||
|
resetPasswordUsername = username;
|
||||||
|
resetPasswordEmail = email;
|
||||||
|
elements.accountResetPasswordUsername.value = "";
|
||||||
|
elements.accountResetPasswordEmail.value = "";
|
||||||
|
elements.accountVerifyPasswordResetText.innerText = TheI18n.GetString(I18nStringKey.kAccountModal_VerifyPasswordResetText, email);
|
||||||
|
elements.accountResetPasswordSection.style.display = "none";
|
||||||
|
elements.accountResetPasswordVerifySection.style.display = "block";
|
||||||
|
} else {
|
||||||
|
elements.accountModalErrorText.innerHTML = result.error!;
|
||||||
|
elements.accountModalError.style.display = "block";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
elements.accountResetPasswordVerifyForm.addEventListener('submit', async e => {
|
||||||
|
e.preventDefault();
|
||||||
|
var code = elements.accountResetPasswordCode.value;
|
||||||
|
var password = elements.accountResetPasswordNewPassword.value;
|
||||||
|
if (password !== elements.accountResetPasswordConfirmNewPassword.value) {
|
||||||
|
elements.accountModalErrorText.innerHTML = TheI18n.GetString(I18nStringKey.kPasswordsMustMatch);
|
||||||
|
elements.accountModalError.style.display = "block";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var result = await auth!.resetPassword(resetPasswordUsername!, resetPasswordEmail!, code, password);
|
||||||
|
if (result.success) {
|
||||||
|
elements.accountResetPasswordCode.value = "";
|
||||||
|
elements.accountResetPasswordNewPassword.value = "";
|
||||||
|
elements.accountResetPasswordConfirmNewPassword.value = "";
|
||||||
|
elements.accountModalSuccessText.innerHTML = TheI18n.GetString(I18nStringKey.kAccountModal_PasswordResetSuccess);
|
||||||
|
elements.accountModalSuccess.style.display = "block";
|
||||||
|
elements.accountResetPasswordVerifySection.style.display = "none";
|
||||||
|
elements.accountLoginSection.style.display = "block";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
elements.accountModalErrorText.innerHTML = result.error!;
|
||||||
|
elements.accountModalError.style.display = "block";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
// Public API
|
// Public API
|
||||||
w.collabvm = {
|
w.collabvm = {
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,13 @@
|
||||||
"kAccountModal_Register": "Register",
|
"kAccountModal_Register": "Register",
|
||||||
"kAccountModal_Verify": "Verify E-Mail",
|
"kAccountModal_Verify": "Verify E-Mail",
|
||||||
"kAccountModal_AccountSettings": "Account Settings",
|
"kAccountModal_AccountSettings": "Account Settings",
|
||||||
|
"kAccountModal_ResetPassword": "Reset Password",
|
||||||
|
|
||||||
"kMissingCaptcha": "Please fill out the captcha.",
|
"kMissingCaptcha": "Please fill out the captcha.",
|
||||||
"kPasswordsMustMatch": "Passwords must match.",
|
"kPasswordsMustMatch": "Passwords must match.",
|
||||||
"kAccountModal_VerifyText": "We sent an E-Mail to {0}. To verify your account, please enter the 8-digit code from the E-Mail below.",
|
"kAccountModal_VerifyText": "We sent an E-Mail to {0}. To verify your account, please enter the 8-digit code from the E-Mail below.",
|
||||||
|
"kAccountModal_VerifyPasswordResetText": "We sent an E-Mail to {0}. To reset your password, please enter the 8-digit code from the E-Mail below.",
|
||||||
|
"kAccountModal_PasswordResetSuccess": "Your password has been changed successfully. You can now log in with your new password.",
|
||||||
|
|
||||||
"kNotLoggedIn": "Not Logged in"
|
"kNotLoggedIn": "Not Logged in"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user