rejetto forum

Alternative login form for modern browsers

LeoNeeson · 19 · 16155

0 Members and 2 Guests are viewing this topic.

Offline LeoNeeson

  • Tireless poster
  • ****
    • Posts: 842
  • Status: On hiatus (sporadically here)
    • View Profile
    • twitter.com/LeoNeeson
Thanks to danny and his idea (in this post), and after spending several hours finding a solution and doing lot of tests, I think we finally have a working workaround solution for login from mobile browsers (that it even work on desktop browsers too).

1. In the "Virtual File System" box, right click on the first element (Home)
2. Properties
3. Diff template
4. Enter this text:
Code: [Select]
[unauthorized]
<h1>{.!Unauthorized.} {.!&#47; Please login&hellip;.}</h1>
{.!Either your user name and password do not match, or you are not permitted to access this resource..}<br>
{.!Please login to access to your account, and check if you have the correct permissions to continue..}<br>

<br>
<fieldset id='login'>
  <legend><img src="/~img27"> {.!Login.}</legend>
  <center>
    <input type='text' id='usr' size='15' placeholder=" Username" value=""><br>
    <input type='password' id='psw' size='15' placeholder=" Password" value=""><br>
    <input type='button' id='lognow' style="width:110px;" value="{.!Login.}" onclick="NewLogin();">
  </center>
</fieldset>
<br>

<script>
function NewLogin() {
  var xhr = new XMLHttpRequest();
  var ThisFolder = window.location;
  var ThisUser = document.getElementById("usr").value;
  var ThisPass = document.getElementById("psw").value;
  var LoginToken = ThisUser+':'+ThisPass;
  xhr.open("GET", "/~login", true);
  xhr.withCredentials = true;
  xhr.setRequestHeader("Authorization", 'Basic ' + btoa(LoginToken));
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
      if (window.location.href.indexOf("~login") != -1) {
        window.location.replace('/?success');
        } else {
          window.location.replace(ThisFolder);
      };
    }
    if (xhr.readyState == 4 && xhr.status == 401) {
      alert("Invalid credentials! \(Wrong username or password\)");
    }
  }
  xhr.send();
}
</script>

Please test it and report the results (remember to create an account first on HFS). I've literally wasted all my free afternoon, but I'm happy with the results!. It may not be perfect, so, feel free to adapt/correct/enhance the code... ;)

Cheers,
Leo.-
« Last Edit: August 25, 2018, 03:08:25 AM by LeoNeeson »
HFS in Spanish (HFS en Español) / How to compile HFS (Tutorial)
» Currently taking a break, until HFS v2.4 get his stable version.


Offline bmartino1

  • Tireless poster
  • ****
    • Posts: 910
  • I'm only trying to help i mean no offense.
    • View Profile
    • My HFS Google Drive Shared Link
thank you leo, the code works fairly well.

I did attempt to add/change css and put form stuff in it as per dany request on what it might have... etc...

here is that code for refference.

Code: [Select]
[unauthorized]

<!-- I should be a EVENT Under the House - "Home icon / " Root Virtual File system!-->
<!-- include css file here-->
    <style> /* below line is write to use google font online  */
@import url(http://fonts.googleapis.com/css?family=Ubuntu);
 
h2{
 background-color: #FEFFED;
 padding: 30px 35px;
 margin: -10px -50px;
 /*text-align:center; */
 border-radius: 10px 10px 0 0;
}
 
hr{
 margin: 10px -50px;
 border: 0;
 border-top: 1px solid #ccc;
 margin-bottom: 40px;
}
 
div.container{
 width: 900px;
 height: 610px;
 margin:35px auto;
 font-family: 'Ubuntu', sans-serif;
}
 
div.main{
 width: 300px;
 padding: 10px 50px 25px;
 /* border: 2px solid gray; */
 border-radius: 10px;
 font-family: raleway;
 float:left;
 margin-top:50px;
}
 
input[type=text],input[type=password]{
 width: 150px;
 height: 40px;
 padding: 5px;
 margin-bottom: 25px;
 margin-top: 5px;
 border: 2px solid #ccc;
 color: #4f4f4f;
 font-size: 16px;
 border-radius: 5px;
}

label{
 color: #464646;
 text-shadow: 0 1px 0 #fff;
 font-size: 14px;
 font-weight: bold;
}

center{
 font-size:32px;
}

.note{
 color:red;
}
 
.valid{
 color:green;
}

.back{
 text-decoration: none;
 border: 1px solid rgb(0, 143, 255);
 background-color: rgb(0, 214, 255);
 padding: 3px 20px;
 border-radius: 2px;
 color: black;
}
 
input[type=button]{
 font-size: 16px;
 background: linear-gradient(#ffbc00 5%, #ffdd7f 100%);
 border: 1px solid #e5a900;
 color: #4E4D4B;
 font-weight: bold;
 cursor: pointer;
 width: 150px;
 border-radius: 5px;
 padding: 10px 0;
 outline:none;
}
 
input[type=button]:hover{
 background: linear-gradient(#ffdd7f 5%, #ffbc00 100%);
}

.fugo{
 float:right;
} </style>

<script>
function NewLogin() {
  var xhr = new XMLHttpRequest();
  var ThisFolder = window.location;
  var ThisUser = document.getElementById("usr").value;
  var ThisPass = document.getElementById("psw").value;
  var LoginToken = ThisUser+':'+ThisPass;
  xhr.open("GET", "/~login", true);
  xhr.withCredentials = true;
  xhr.setRequestHeader("Authorization", 'Basic ' + btoa(LoginToken));
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
      if (window.location.href.indexOf("~login") != -1) {
        window.location.replace('/?success');
        } else {
          window.location.replace(ThisFolder);
      };
    }
    if (xhr.readyState == 4 && xhr.status == 401) {
      alert("Invalid credentials! \(Wrong username or password\)");
    }
  }
  xhr.send();
}
</script>
<h1>{.!Unauthorized.} {.!&#47; Please login&hellip;.}</h1>
{.!Either your user name and password do not match, or you are not permitted to access this resource..}<br>
{.!Please login to access to your account, and check if you have the correct permissions to continue..}<br>
<br>

<div class="container">
  <div class="main">
  <div align="left">
<!-- <h2>Login Form</h2><hr/> -->
<!-- <form id="form_id" name="myform"> -->
<fieldset id='login'>
  <legend><img src="/~img27"> {.!Login.}</legend>
  <center>
  <label for="uname">User Name :</label></br>
    <input type='text' class="form-control" id='usr' tabindex="1" size='15' placeholder=" Username" value="" required><br>
    <span class='error-message' id='uname-error'></span>

<label>Password :</label></br>
<input type='password' class="form-control" id='psw' tabindex="2" size='15' placeholder=" Password" value="" required><br>
    <span class='error-message' id='pw-error'></span>

<input type='button' tabindex="3" class="btn btn-default" id='lognow' style="width:110px;" value="{.!Login.}" onclick="NewLogin();">
    <span class='error-message' id='submit-error'></span>

<!--    <label><input type="checkbox" checked="checked" name="remember"> Remember me </label> -->
<!-- <button type="button" class="cancelbtn">Cancel</button> <span class="psw">Forgot <a href="#">password?</a></span> -->
<!-- </form> -->

 </center>
</fieldset>
</div>
  </div>
</div>
<br>
</br>
<!-- Did I work? -->
<p> User: %user% @ IP: %ip% </p>
</div>

i had did a test of 2 vitural folder eacch with 1 acount acess split between 2 accounts.

the unathoruzed code will log you in 1 for that folder (it doen't keep you loged in if i leave to another area.)

also the only way i could eror was to click ont he resouce and hit cancle
thus i hit the even t created 404 login.
but you err wrong credential broungh back the default login box (had to hit cancle) before i saw the alert.

other wise, exclent code, and thank you for this.

Also looks like o need to relearn the xml httl request and HTML code :/
https://stackoverflow.com/questions/28238514/login-form-valiation-using-xmlhttprequest
« Last Edit: August 29, 2018, 11:53:56 PM by bmartino1 »
Files I have snagged and share can be found on my google drive:

https://drive.google.com/drive/folders/1qb4INX2pzsjmMT06YEIQk9Nv5jMu33tC?usp=sharing


Offline LeoNeeson

  • Tireless poster
  • ****
    • Posts: 842
  • Status: On hiatus (sporadically here)
    • View Profile
    • twitter.com/LeoNeeson
BREAKING NEWS!! :D v2.0 released! (see below)



For a long time I was convinced that having a form-based 'login' and a truly working 'logout' (totally independent of which browser you use), was something technically impossible to accomplish, just because a limitation of the Basic Authentication scheme (which HFS makes use).

Although this remains to be true (Basic Auth scheme impose limitations), recently I've discovered that HFS also supports "Digest access authentication" (besides the "Basic access authentication"). This lets HFS manage logins much better, since it makes use of a "session ID" cookie (named HFS_SID_), which gives us a possibility of having a true logout system. 8)

But, after days of testings, I've found a bug (or an imperfect implementation in the code) that is preventing HFS to forget a previously logged-in session (this breaks the logout system), and was reported HERE. I'm always talking about using a form-based login and not the internal browser popup login (to test this, you have to click cancel on that popup).

Summarizing: we could have a true logout, when this bug is fixed, and optionally, we will also need to modify the template to avoid opening the browser's login popup, since we will handle the login, only through Ajax (I've also posted there an idea to fix that too).



» How to install:
1. Be sure of use the default login of HFS v2.3m or the legacy template.*
2. In the "Virtual File System" box, right click on the first element (Home)
3. Properties
4. Diff template
5. Enter the text contained on Unauthorized-2.txt
* = Note: this diff-template could also work with another templates, but it's unstested.



Differences with v1.0
- Using now a POST request, which is more secure than GET method.
- Enhanced password security, by using Digest scheme instead of Basic Auth.
(jQuery-free, pure plain JavaScript with no dependencies other than md5.js)

Please report back if you find problems, or want to leave any suggestions or opinions about this. :)

Cheers,
Leo.-
HFS in Spanish (HFS en Español) / How to compile HFS (Tutorial)
» Currently taking a break, until HFS v2.4 get his stable version.


Offline NaitLee

  • Tireless poster
  • ****
    • Posts: 203
  • Computer-brain boy
    • View Profile
Successfully introduced this new login system to my template just now! Please wait for my next update!

Hint: If you put a login form below the [unauthorized] section, you can also add this to your template:

Code: [Select]
[login0]
{.$unauthorized.}

Then view http://127.0.0.1/~login0 (must root, not subfolders), you get your login form without showing the browser's one! ;)
And then you can replace all <a href="~login"> to <a href="/~login0">. Have fun!
« Last Edit: May 04, 2020, 11:55:26 AM by NaitLee »
"Computation is not forbidden magic."
Takeback Template | PHFS


Offline LeoNeeson

  • Tireless poster
  • ****
    • Posts: 842
  • Status: On hiatus (sporadically here)
    • View Profile
    • twitter.com/LeoNeeson
@NaitLee: Thanks for your suggestion. :) I had something similar on my mind, but instead of using ~login0, using ~signin which is an alternate terminology for login.
HFS in Spanish (HFS en Español) / How to compile HFS (Tutorial)
» Currently taking a break, until HFS v2.4 get his stable version.


Offline Rapid

  • Occasional poster
  • *
    • Posts: 49
    • View Profile
    • R&Q Portal
Hi Leo!
Could you make a new version for 2.4?
As 2.4 has new functions like MD5 - it would be nice to compare if it work as expected.

I'm using a HW AES, so it should work much faster than JS function.

And I can't find "Logout" button using default 2.4's template.

Found "logout" button.

Very strange logic. When I put just  any login name, it saves as %user%
« Last Edit: May 07, 2020, 05:36:53 PM by Rapid »


Offline Mars

  • Operator
  • Tireless poster
  • *****
    • Posts: 2059
    • View Profile
for an md5 macro, you must first add OverbyteicsMD5 in 'uses', optionally OverbyteicsSha1
then we add the necessary macros

in this case we take the opportunity to introduce the 64 and sha1 encoding macros available easily

Code: [Select]
    if name = 'encode md5' then  // only for text strings, otherwise use 'md5 file' for binary files
      result:=strMD5(p);

    if name = 'encode sha1' then
      result:=SHA1ofStr(p);

    if name = 'encode 64' then
      result:=base64encode(p);

    if name = 'decode 64' then
      result:=base64decode(p);

// just above these macros
    if name = 'encodeuri' then
      encodeuri();

    if name = 'decodeuri' then
      result:=decodeURL(p);

But to satisfy the rebetto who loves the minimum evolution, we could make a variant allowing an evolution by grouping everything in a macro with various parameters but that could complicate the writing

{.encode|[md5,64,sha1,...]| ..... .}
{.decode|[64,...]| ..... .}
« Last Edit: May 07, 2020, 04:23:15 PM by Mars »


Offline Rapid

  • Occasional poster
  • *
    • Posts: 49
    • View Profile
    • R&Q Portal
Hi Mars,

From whatsnew of 2.4:

Quote
VER 2.4
propaganda
  New mobile-friendly template
/propaganda
+ new default template
+ {.set item|name.}
+ {.get item|icon.}
+ {.set cfg.}
+ cache for jquery and template sections
+ new template commands: base64, base64decode, md5, sha1
...


Offline LeoNeeson

  • Tireless poster
  • ****
    • Posts: 842
  • Status: On hiatus (sporadically here)
    • View Profile
    • twitter.com/LeoNeeson
Hi Rapid! I will split my answer, to make it more easier to understand...

Could you make a new version for 2.4?
I could try to do it, but on the next week I'll have very little free time (next Monday I will start to work again), so that could take me some days/weeks, please be patient. Currently, this is meant to work with the default template of HFS v2.3m (which you can install on the latest v2.4, and it should work normally).

As 2.4 has new functions like MD5 - it would be nice to compare if it work as expected.
I must explain something: as you may already know (since you are a programmer), HFS internally had the MD5 function since 10 years ago (it's not something new), but recently on v2.4, a MD5's macro was added (which enables you to use it on a template). This was added along with Base64 (and it was discussed here).

But for the login you can NOT use the MD5's macro, since macros are executed only at server level. And the MD5 hashing of the login password must be done at client level, before you sent it to the server (so we must use JavaScript to do the MD5 hashing).

You could test the "new" macro functions of HFS v2.4 (for Base64, MD5, SHA1), but the hashing macros are not useful to the login. For example, see this 'diff template' that show those macros (source):

Code: [Select]
[]
<html><body>
{.set|encodedTest| {.base64|this object will store some %symbols% in the javascript space, so that libs can read them.}.}
{.^encodedTest.}
<hr>
The MD5 of "abc" is: {.md5|abc.}
<hr>
MD5 of "encodedTest" variable content: {.md5|{.^encodedTest.}.}
<hr>
SHA1 of "encodedTest" variable content: {.sha1|{.^encodedTest.}.}
<hr>
{.base64decode|{.^encodedTest.}.}
<hr>
{.base64decode|VGhpcyBpcyBhIHNhbXBsZSB0ZXh0.}
<hr>
{.base64decode|dGhpcyBvYmplY3Qgd2lsbCBzdG9yZSBzb21lICVzeW1ib2xzJSBpbiB0aGUgamF2YXNjcmlwdCBzcGFjZSwgc28gdGhhdCBsaWJzIGNhbiByZWFkIHRoZW0= .}
<hr>
</body></html>

(This was only tested with HFS v2.4 RC4, not RC5)

And I can't find "Logout" button using default 2.4's template.
If you are trying to test the logout, at the moment, you must install the old template of HFS v2.3m. What is being discussed here is totally independent of the template, since there we discuss the logout function at server level. If you want to use the logout button on the default 2.4's template, you will have to wait some days until I complete it the adaptation. Stay tuned for news/updates (perhaps some other user, like DJ, could to this faster than me, since he is expert on modern templates).

(In the next few days I will be less active in the forum, but I will still be on the lookout for anything new here)
Cheers,
Leo.-
« Last Edit: May 08, 2020, 12:26:38 AM by LeoNeeson »
HFS in Spanish (HFS en Español) / How to compile HFS (Tutorial)
» Currently taking a break, until HFS v2.4 get his stable version.


Offline Rapid

  • Occasional poster
  • *
    • Posts: 49
    • View Profile
    • R&Q Portal
Quote
But for the login you can NOT use the MD5's macro
You are totally right! Sorry.


Offline rejetto

  • Administrator
  • Tireless poster
  • *****
    • Posts: 13510
    • View Profile
leo is right, you MAY use the server-side md5, but that would break the security and make the md5 a waste of time :)

Modern browsers have sha1 and sha256 but not md5

Code: [Select]
function digest(data, method='SHA-1') {
  return Array.from(new Uint8Array(await crypto.subtle.digest(method, new TextEncoder().encode(data))))
      .map(b => b.toString(16).padStart(2, '0')).join('')
}

digestMessage('test').then(x=> console.log(x))

also, md5 today is considered not very strong, so i think we should go for sha1 or sha256.
compatibility seems quite good
https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Browser_compatibility

templates who want to have the feature on older browser can use this
https://github.com/geraintluff/sha256/blob/gh-pages/sha256.min.js
otherwise they can just send plain-text.

new delphi has all of these already embedded.
http://docwiki.embarcadero.com/Libraries/Rio/en/System.Hash.THashSHA2


Offline rejetto

  • Administrator
  • Tireless poster
  • *****
    • Posts: 13510
    • View Profile
Code: [Select]
      if goodPassword(data.postVars.values['__PASSWORD_SHA256'], strSHA256)
      or goodPassword(data.postVars.values['__PASSWORD_MD5'], strMD5)
      or (data.postVars.values['__PASSWORD'] = data.account.pwd) then

next release ;-)


Offline Mars

  • Operator
  • Tireless poster
  • *****
    • Posts: 2059
    • View Profile
Why stop now while everything is going so well  ;)

      if goodPassword(data.postVars.values['__PASSWORD_SHA256'], strSHA256)
      or goodPassword(data.postVars.values['__PASSWORD_MD5'], strMD5)
      or goodPassword(data.postVars.values['__PASSWORD_B64'], strB64)
      or (data.postVars.values['__PASSWORD'] = data.account.pwd) then

https://www.base64encoder.io/javascript/

we could even avoid indicating the type of encryption when sending the form in case of interception of frames
     if goodPassword(data.postVars.values['__PASSWORD'], strSHA256)
      or goodPassword(data.postVars.values['__PASSWORD'], strMD5)
      or goodPassword(data.postVars.values['__PASSWORD'], strB64)
      or (data.postVars.values['__PASSWORD'] = data.account.pwd) then
« Last Edit: May 10, 2020, 03:16:54 PM by Mars »


Offline rejetto

  • Administrator
  • Tireless poster
  • *****
    • Posts: 13510
    • View Profile
there's no need for base64, and it's not hashing, no security.
i explained reasons for sha256