You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

443 lines
14 KiB

  1. // login.js
  2. // don't remove this line (used in test)
  3. window.disable_signup = {{ disable_signup and "true" or "false" }};
  4. window.login = {};
  5. window.verify = {};
  6. login.bind_events = function() {
  7. $(window).on("hashchange", function() {
  8. login.route();
  9. });
  10. $(".form-login").on("submit", function(event) {
  11. event.preventDefault();
  12. var args = {};
  13. args.cmd = "login";
  14. args.usr = ($("#login_email").val() || "").trim();
  15. args.pwd = $("#login_password").val();
  16. args.device = "desktop";
  17. if(!args.usr || !args.pwd) {
  18. frappe.msgprint("{{ _("Both login and password required") }}");
  19. return false;
  20. }
  21. login.call(args);
  22. return false;
  23. });
  24. $(".form-signup").on("submit", function(event) {
  25. event.preventDefault();
  26. var args = {};
  27. args.cmd = "frappe.core.doctype.user.user.sign_up";
  28. args.email = ($("#signup_email").val() || "").trim();
  29. args.redirect_to = get_url_arg("redirect-to") || '';
  30. args.full_name = ($("#signup_fullname").val() || "").trim();
  31. if(!args.email || !valid_email(args.email) || !args.full_name) {
  32. login.set_indicator("{{ _("Valid email and name required") }}", 'red');
  33. return false;
  34. }
  35. login.call(args);
  36. return false;
  37. });
  38. $(".form-forgot").on("submit", function(event) {
  39. event.preventDefault();
  40. var args = {};
  41. args.cmd = "frappe.core.doctype.user.user.reset_password";
  42. args.user = ($("#forgot_email").val() || "").trim();
  43. if(!args.user) {
  44. login.set_indicator("{{ _("Valid Login id required.") }}", 'red');
  45. return false;
  46. }
  47. login.call(args);
  48. return false;
  49. });
  50. $(".btn-ldap-login").on("click", function(){
  51. var args = {};
  52. args.cmd = "{{ ldap_settings.method }}";
  53. args.usr = ($("#login_email").val() || "").trim();
  54. args.pwd = $("#login_password").val();
  55. args.device = "desktop";
  56. if(!args.usr || !args.pwd) {
  57. login.set_indicator("{{ _("Both login and password required") }}", 'red');
  58. return false;
  59. }
  60. login.call(args);
  61. return false;
  62. });
  63. }
  64. login.route = function() {
  65. var route = window.location.hash.slice(1);
  66. if(!route) route = "login";
  67. login[route]();
  68. }
  69. login.reset_sections = function(hide) {
  70. if(hide || hide===undefined) {
  71. $("section").toggle(false);
  72. }
  73. $('section .indicator').each(function() {
  74. $(this).removeClass().addClass('indicator').addClass('blue')
  75. .text($(this).attr('data-text'));
  76. });
  77. }
  78. login.login = function() {
  79. login.reset_sections();
  80. $(".for-login").toggle(true);
  81. }
  82. login.steptwo = function() {
  83. login.reset_sections();
  84. $(".for-login").toggle(true);
  85. }
  86. login.forgot = function() {
  87. login.reset_sections();
  88. $(".for-forgot").toggle(true);
  89. }
  90. login.signup = function() {
  91. login.reset_sections();
  92. $(".for-signup").toggle(true);
  93. }
  94. // Login
  95. login.call = function(args, callback) {
  96. login.set_indicator("{{ _('Verifying...') }}", 'blue');
  97. return frappe.call({
  98. type: "POST",
  99. args: args,
  100. callback: callback,
  101. freeze: true,
  102. statusCode: login.login_handlers
  103. });
  104. }
  105. login.set_indicator = function(message, color) {
  106. $('section:visible .indicator')
  107. .removeClass().addClass('indicator').addClass(color).text(message)
  108. }
  109. login.login_handlers = (function() {
  110. var get_error_handler = function(default_message) {
  111. return function(xhr, data) {
  112. if(xhr.responseJSON) {
  113. data = xhr.responseJSON;
  114. }
  115. var message = default_message;
  116. if (data._server_messages) {
  117. message = ($.map(JSON.parse(data._server_messages || '[]'), function(v) {
  118. // temp fix for messages sent as dict
  119. try {
  120. return JSON.parse(v).message;
  121. } catch (e) {
  122. return v;
  123. }
  124. }) || []).join('<br>') || default_message;
  125. }
  126. if(message===default_message) {
  127. login.set_indicator(message, 'red');
  128. } else {
  129. login.reset_sections(false);
  130. }
  131. };
  132. }
  133. var login_handlers = {
  134. 200: function(data) {
  135. console.log(data);
  136. if(data.verification) {
  137. login.set_indicator("{{ _("Success") }}", 'green');
  138. var continue_otp = function(setup_completed,method_prompt){
  139. $('.login-content').empty().append($('<div>').attr({'id':'otp_div'}).html(
  140. '<form class="form-verify">\
  141. <div class="page-card-head">\
  142. <span class="indicator blue" data-text="Verification">Verification</span>\
  143. </div>\
  144. <input type="text" id="login_token" class="form-control" placeholder="Verification Code" required autocomplete="off" autofocus="">\
  145. <button type="submit" class="btn btn-sm btn-primary btn-block" id="verify_token">Verify</button>\
  146. </form>'));
  147. verify_token();
  148. if (!setup_completed){
  149. var qrcode = $('<div>')
  150. qrcode.attr('id','qrcode_div');
  151. qrcode.css('text-align','center');
  152. var direction = $('<div>').attr('id','qr_info').text(method_prompt || 'Scan QR Code and enter the resulting code displayed');
  153. var qrimg = $('<img>');
  154. qrimg.attr('src','data:image/svg+xml;base64,' + data.verification.qrcode);
  155. qrcode.append(direction);
  156. qrcode.append(qrimg);
  157. $('#otp_div').prepend(qrcode);
  158. } else {
  159. var qrcode = $('<div>').attr('id','qrcode_div');
  160. var direction = $('<div>').attr('id','qr_info').text(method_prompt || 'Enter Code displayed in OTP App');
  161. direction.attr('style','padding-bottom:10px;');
  162. qrcode.append(direction);
  163. $('#otp_div').prepend(qrcode)
  164. }
  165. }
  166. var continue_sms = function(setup_completed,method_prompt){
  167. $('.login-content').empty().append($('<div>').attr({'id':'otp_div'}).html(
  168. '<form class="form-verify">\
  169. <div class="page-card-head">\
  170. <span class="indicator blue" data-text="Verification">Verification</span>\
  171. </div>\
  172. <input type="text" id="login_token" class="form-control" placeholder="Verification Code" required="" autofocus="">\
  173. <button class="btn btn-sm btn-primary btn-block" id="verify_token">Verify</button>\
  174. </form>'));
  175. verify_token();
  176. if (!setup_completed){
  177. var sms_div = $('<div>').attr({'id':'sms_div','style':'margin-bottom: 20px;'});
  178. var direction = $('<div>').attr({'id':'sms_info','style':'margin-bottom: 15px;'}).text('Enter phone number to send verification code');
  179. sms_div.append(direction);
  180. sms_div.append($('<div>').attr({'id':'sms_code_div'}).html(
  181. '<div class="form-group text-center">\
  182. <input type="text" id="phone_no" class="form-control" placeholder="2347001234567" required="" autofocus="">\
  183. <button class="btn btn-sm btn-primary" id="submit_phone_no" >Send SMS</button>\
  184. </div><hr>'));
  185. $('#otp_div').prepend(sms_div);
  186. $('#submit_phone_no').on('click',function(){
  187. frappe.call({
  188. method: "frappe.core.doctype.user.user.send_token_via_sms",
  189. args: {'phone_no': $('#phone_no').val(), 'tmp_id':data.tmp_id },
  190. freeze: true,
  191. callback: function(r) {
  192. if (r.message){
  193. $('#sms_div').empty().append(
  194. '<p class="lead">SMS sent.<br><small><small>Enter verification code received</small></small></p><hr>'
  195. );
  196. } else {
  197. $('#sms_div').empty().append(
  198. '<p class="lead">SMS not sent</p><hr>'
  199. );
  200. }
  201. }
  202. });
  203. })
  204. } else {
  205. var smscode = $('<div>').attr('id','smscode_div');
  206. var direction = $('<div>').attr('id','qr_info').text(method_prompt || 'Enter verification code sent to registered phone number');
  207. direction.attr('style','padding-bottom:10px;');
  208. smscode.append(direction);
  209. $('#otp_div').prepend(smscode)
  210. }
  211. }
  212. var continue_email = function(setup_completed,method_prompt){
  213. $('.login-content').empty().append($('<div>').attr({'id':'otp_div'}).html(
  214. '<form class="form-verify">\
  215. <div class="page-card-head">\
  216. <span class="indicator blue" data-text="Verification">Verification</span>\
  217. </div>\
  218. <input type="text" id="login_token" class="form-control" placeholder="Verification Code" required="" autofocus="">\
  219. <button class="btn btn-sm btn-primary btn-block" id="verify_token">Verify</button>\
  220. </form>'));
  221. verify_token();
  222. if (!setup_completed){
  223. var email_div = $('<div>').attr({'id':'email_div','style':'margin-bottom: 20px;'});
  224. email_div.append('<p>Verification code email will be sent to registered email address. Enter code received below</p>')
  225. $('#otp_div').prepend(email_div);
  226. frappe.call({
  227. method: "frappe.core.doctype.user.user.send_token_via_email",
  228. args: {'tmp_id':data.tmp_id },
  229. callback: function(r) {
  230. if (r.message){
  231. } else {
  232. $('#email_div').empty().append(
  233. '<p>Email not sent</p><hr>'
  234. );
  235. }
  236. }
  237. });
  238. } else {
  239. if (method_prompt){
  240. var emailcode = $('<div>').attr('id','emailcode_div');
  241. var direction = $('<div>').attr('id','qr_info').text(method_prompt || 'Verification code email will be sent to registered email address. Enter code received below');
  242. direction.attr('style','padding-bottom:10px;');
  243. emailcode.append(direction);
  244. $('#otp_div').prepend(emailcode);
  245. } else {
  246. var emailcode = $('<div>').attr('id','emailcode_div');
  247. var direction = $('<div>').attr('id','qr_info').text('Verification code email not sent');
  248. direction.attr('style','padding-bottom:10px;');
  249. emailcode.append(direction);
  250. $('#otp_div').prepend(emailcode)
  251. }
  252. }
  253. }
  254. if (data.verification.method_first_time){
  255. // $('.login-content').empty().append('<div id="verification_method">\
  256. // <div>\
  257. // <p class="lead">Select verification Method <br>\
  258. // <small><small><small class="text-muted">method may be changed later in settings</small></small></small></p>\
  259. // </div>\
  260. // <div class="form-check">\
  261. // <label class="form-check-label">\
  262. // <input class="form-check-input" type="radio" name="method" value="OTP App" checked>\
  263. // OTP App\
  264. // </label>\
  265. // </div>\
  266. // <div class="form-check">\
  267. // <label class="form-check-label">\
  268. // <input class="form-check-input" type="radio" name="method" value="SMS">\
  269. // SMS\
  270. // </label>\
  271. // </div>\
  272. // <div class="form-check disabled">\
  273. // <label class="form-check-label">\
  274. // <input class="form-check-input" type="radio" name="method" value="Email">\
  275. // Email\
  276. // </label>\
  277. // </div>\
  278. // <button id="submit_method" class="btn btn-sm btn-primary">Continue</button>\
  279. // </div>')
  280. // if (data.verification.restrict_method){
  281. // $('input[name=method]').each(function(){
  282. // if ($(this).val() != data.verification.restrict_method){
  283. // $(this).attr('disabled',true)
  284. // }
  285. // })
  286. // }
  287. // $('#submit_method').on('click',function(event){
  288. if (data.verification.method == 'OTP App'){
  289. continue_otp(setup_completed=false);
  290. } else if (data.verification.method == 'SMS'){
  291. continue_sms(setup_completed=false);
  292. } else if (data.verification.method == 'Email'){
  293. continue_email(setup_completed=false);
  294. }
  295. // frappe.call({
  296. // method: "frappe.core.doctype.user.user.set_verification_method",
  297. // args: {'tmp_id':data.tmp_id, 'method': $('input[name=method]:checked').val()},
  298. // callback: function(r) { }
  299. // });
  300. // });
  301. } else {
  302. if (data.verification.method == 'OTP App'){
  303. console.log(data.verification.totp_uri)
  304. continue_otp(setup_completed = data.verification.otp_setup_completed);
  305. } else if (data.verification.method == 'SMS'){
  306. continue_sms(setup_completed=true, method_prompt=data.verification.prompt);
  307. console.log('SMS');
  308. } else if (data.verification.method == 'Email'){
  309. continue_sms(setup_completed=true, method_prompt=data.verification.prompt);
  310. }
  311. }
  312. document.cookie = "tmp_id="+data.tmp_id;
  313. //verify_token();
  314. return false;
  315. } else if(data.message == 'Logged In'){
  316. login.set_indicator("{{ _("Success") }}", 'green');
  317. window.location.href = get_url_arg("redirect-to") || data.home_page;
  318. } else if(data.message=="No App") {
  319. login.set_indicator("{{ _("Success") }}", 'green');
  320. if(localStorage) {
  321. var last_visited =
  322. localStorage.getItem("last_visited")
  323. || get_url_arg("redirect-to");
  324. localStorage.removeItem("last_visited");
  325. }
  326. if(data.redirect_to) {
  327. window.location.href = data.redirect_to;
  328. }
  329. if(last_visited && last_visited != "/login") {
  330. window.location.href = last_visited;
  331. } else {
  332. window.location.href = data.home_page;
  333. }
  334. } else if(window.location.hash === '#forgot') {
  335. if(data.message==='not found') {
  336. login.set_indicator("{{ _("Not a valid user") }}", 'red');
  337. } else if (data.message=='not allowed') {
  338. login.set_indicator("{{ _("Not Allowed") }}", 'red');
  339. } else {
  340. login.set_indicator("{{ _("Instructions Emailed") }}", 'green');
  341. }
  342. } else if(window.location.hash === '#signup') {
  343. if(cint(data.message[0])==0) {
  344. login.set_indicator(data.message[1], 'red');
  345. } else {
  346. login.set_indicator("{{ _('Success') }}", 'green');
  347. frappe.msgprint(data.message[1])
  348. }
  349. //login.set_indicator(__(data.message), 'green');
  350. }
  351. },
  352. 401: get_error_handler("{{ _("Invalid Login. Try again.") }}"),
  353. 417: get_error_handler("{{ _("Oops! Something went wrong") }}")
  354. };
  355. return login_handlers;
  356. } )();
  357. frappe.ready(function() {
  358. login.bind_events();
  359. console.log("Why");
  360. if (!window.location.hash) {
  361. window.location.hash = "#login";
  362. } else {
  363. $(window).trigger("hashchange");
  364. }
  365. $(".form-signup, .form-forgot").removeClass("hide");
  366. $(document).trigger('login_rendered');
  367. });
  368. var verify_token = function(event) {
  369. $(".form-verify").on("submit", function(eventx) {
  370. eventx.preventDefault();
  371. var args = {};
  372. args.cmd = "login";
  373. args.otp = $("#login_token").val();
  374. args.tmp_id = frappe.get_cookie('tmp_id');
  375. if(!args.otp) {
  376. frappe.msgprint('{{ _("Login token required") }}');
  377. return false;
  378. }
  379. login.call(args);
  380. return false;
  381. });
  382. }