rejetto forum

Software => HFS ~ HTTP File Server => Bug reports => Topic started by: LeoNeeson on April 25, 2020, 10:46:27 PM

Title: Bug: Logout function at server level [Fixed]
Post by: LeoNeeson on April 25, 2020, 10:46:27 PM
SOLVED! (https://i.imgur.com/lgmXfyh.gif)

» Edit #3 (12-05-2020): Now logout is 100% perfect on v2.4 Alpha 8 (https://github.com/rejetto/hfs2/releases/tag/v2.4-alpha08).

» Edit #2 (09-05-2020): This was almost fixed by Rejetto on v2.4 Alpha 5 (https://github.com/rejetto/hfs2/releases/tag/v2.4-alpha05).

» Edit #1 (07-05-2020): I had to edit the title (Confirmed bug: HFS doesn't discard previous auth sessions), because it seems some people have not understood it. Like the title says: HFS doesn't discard the 'session ID' of a authenticated user, when he logouts using a form-based login (we are talking about the 'logout' function at server level, and to reproduce the bug, the user must not use the native login function of the browser).



@Message to Rejetto, Mars, SilentPliz or any other Delphi/Pascal programmer:

• Steps to reproduce this possible bug:
1) Use default 2.3's template (http://rejetto.com/forum/index.php?topic=13082.0) along with this form-based login (diff-template) (http://rejetto.com/forum/index.php?topic=13054.msg1065523#msg1065523).
2) Create a user and have some shared folders protected with a password.
3) Open your browser and use the form-based login to authenticate (do NOT enter credentials on the browser's internal popup login, hit cancel on that popup window).
4) Open several password-protected folders, in several browser tabs, and navigate thought those sub-folders if you want.
5) Click on the 'Logout' button, change to another tab, and navigate on some password-protected resource (you will be automatically logged in again!).

» Why this is a HFS bug and not a fault in the template?...
Please follow the next steps and you will find how it SHOULD work: :)
A) Follow steps 1 to 5, but after clicking on the logout, temporary close HFS.
B) Open HFS again, and now try to navigate on some password-protected resource (you will NOT be automatically logged in!). Yay! :D This demonstrates that HFS is not discarding (in his memory) the association between some previously logged in USER and the session ID (SID) he used.

- You may say: but this could be solved on the client side by generating a new 'session ID' cookie. You are right, but if the user had several tabs open (or if he goes back in the browser history), he will be automatically logged in back again, and this is unwanted (and insecure).

- What this means?: This means that when this bug is fixed, no matter if you go back in your browser, once you logout you can't access any password protected resource anymore (no matter if you had multiple tabs open).

If you have any questions or difficulties on reproducing this, please ask me. This thread is open to anyone, so, don't be afraid to leave your question... ;)

Cheers,
Leo.-
Title: Re: Confirmed bug: HFS doesn't discard previous auth sessions
Post by: LeoNeeson on April 29, 2020, 05:56:56 PM
@Rejetto (https://rejetto.com/forum/index.php?action=profile;u=1): (have you read this thread or not? (https://i.imgur.com/KfDeBfQ.gif)). If you read this, please leave a comment about this issue (your opinion is very important). Thanks! :)



To make you easier to analyze the code, this is the function we need to optimize/fix:

Quote
  sessionSetup();
  if data.postVars.indexOfName('__USER') >= 0 then
    begin
    s:=data.postVars.values['__USER'];
    data.account:=getAccount(s);
    if data.account = NIL then
      if s = '' then // logout
        begin
        s:='ok';
        data.usr:='';
        data.pwd:='';
        end
      else
        s:='username not found'
    else
      begin
      data.usr:=s;
      { I opted to use double md5 for this authentication method so that in the
        future we may make this work even if we store hashed password on the server.
        In such case we would not be able to calculate pwd+sessionID because we'd had no clear pwd.
        By relying on md5(pwd) instead of pwd, we will avoid such problem. }
      s:=data.postVars.values['__PASSWORD_MD5'];
      if (s > '') and (s = strMD5(strMD5(data.account.pwd)+data.sessionID))
          or (data.postVars.values['__PASSWORD'] = data.account.pwd) then
        begin
        s:='ok';
        data.pwd:=data.account.pwd;
        data.sessionSet('user', data.usr);
        data.sessionSet('password', data.pwd);
        end
      else
        begin
        s:='bad password';
        data.account:=NIL;
        data.usr:='';
        end;
      end;
    if data.postVars.values['__AJAX'] = '1' then
      begin
      replyWithString(s);
      exit;
      end;
    end;

That is found on main.pas.

@anyone non-programmer: that's Delphi code, not JavaScript.



» EDIT: Please see my next message (http://rejetto.com/forum/index.php?topic=13286.msg1065529#msg1065529) to find a possible fix. :)

Could someone please confirm if is able to reproduce this error... :-\
Cheers,
Leo.-
 
Title: Re: Confirmed bug: possible fix...
Post by: LeoNeeson on April 29, 2020, 10:12:04 PM
OK, I'll make some tests. What do you think about this?...

Quote
.......
    if data.account = NIL then
      if s = '' then // logout
        begin
        s:='ok';
        data.usr:='';
        data.pwd:='';
        data.sessionSet('user', data.usr); //add by leo
        data.sessionSet('password', data.pwd); //add by leo
        Kickidleconnections1Click(NIL); //add by leo
        end
      else
        s:='username not found'
    else
.......

I'll report later, after doing several tests...

@Mars: are you OK with me? (because you seem to ignore my posts, and you almost never participate or reply on any of my messages, even when I quote you). Do you feel offended by something I've said in the past?. Please, forgive me if I've said something that offended you... :-[ :'(
 
Title: Re: Confirmed bug: problem fixed!
Post by: LeoNeeson on April 29, 2020, 11:06:48 PM
Woohoo!! That fix gloriously WORKS! :D I've compiled HFS by myself and I can confirm THIS (https://rejetto.com/forum/index.php?topic=13286.msg1065529#msg1065529) fix totally solves the logout problem! Now we could have a perfectly working logout function, by using a form-based login (https://rejetto.com/forum/index.php?topic=13054.msg1065523#msg1065523). If you have a better approach to solve this issue, please feel free to submit your proposed code.

» EDIT: I'm now awaiting a reply from Rejetto, and see if he approves this fix (https://rejetto.com/forum/index.php?topic=13286.msg1065529#msg1065529) for HFS v2.4 RC5 (https://rejetto.com/forum/index.php?topic=13060.0). ;)

Cheers,
Leo.-
Title: Re: Confirmed bug: HFS doesn't discard previous auth sessions
Post by: SilentPliz on April 30, 2020, 03:15:46 PM

Hi Leo! :)

I tried today to compile the 2.3m of rejetto including your modifications ... and it works !!!

I used the diff.tpl provided by you, and tested it on two browsers (FF and Chrome) at the same time, with two different user accounts.

The logout works correctly, as well as the 'Digest access authentication'.

So ... Bravo!! and Bravo!! Well done !! 8)
Since the time users requested these features, this is a big step forward for hfs. It's a great work.

The only small questioning I have is the excessive presence of the browser 'default login box'.
If it were installed as is, the user, I think, would miss using the 'Digest access authentication' feature.
But it's just a detail of form, which must be able to be resolved.

Congratulations again and thank you for your work. :)

We await with amazement and tremors, the Boss' verdict! :D
Title: Re: Confirmed bug: HFS doesn't discard previous auth sessions
Post by: LeoNeeson on April 30, 2020, 06:30:56 PM
Thank you for the compliments (I truly appreciate them). :)

» Technical explanation: Although my fix works, it's not 100% perfect. With my fix, we clear the user & pass data stored along with the session (that's good), and then we kick idle connections (that's not so good, but it's needed at the moment). This is all fine, but the best thing would be removing the 'session ID' from 'sessions.objects' list (and then, perhaps would not be needed to kick idle connections), all this, along with issuing a new 'session ID' cookie at the moment of logout (but it's not clear if that's of much help). Why kicking idle connections is not perfect? because, besides of being a dirty trick, if the user is STILL downloading a password protected file, and he logouts but continues navigating, sometimes he could get logged in back again. That's why I say that we would need a better approach than only kicking idle connections, and that we must remove the 'session ID' (on the server) from 'sessions' list at the moment of logout.

» Design/template: I recognize my form based login is ugly for the new template of v2.4 (it need to be adapted to the new template). Perhaps a modal would fit best, since it doesn't take space, and it's easy to add, or a hidden input (that shows up when you click on it), like the current search box.

Feel anyone free to contribute on all this, and I'm sure Rejetto would come up with great new fresh ideas, for both: on the design and the technical side. ;)

Cheers,
Leo.-
Title: About SessionID at logout...
Post by: LeoNeeson on May 04, 2020, 02:42:25 AM
I would like to bring attention to this thread, because even if Rejetto is not interested on incorporating this fix on a final release of HFS (which is absolutely fine), we still need "some light" on this issue...

@Rejetto: since you internally know how sessions are managed by HFS, could you please say us how we could remove the 'session ID' from 'sessions.objects' list? (to add this on the logout function, and make it work properly). Or at least saying us if we are doing this fix in the right way. My proposed fix works fine (https://rejetto.com/forum/index.php?topic=13286.msg1065529#msg1065529), but I consider is not perfect. What do you think about it? (can it get better?)

Doing this, we could mark this issue as fixed, and give a conclusion to this thread, and if you approve the changes, at least this fix could be added on the SilentPliz version (thanks!). :)

We await with amazement and tremors, the Boss' verdict! :D
It seems he overlooked and missed this thread, with all the fuss of Delphi 10 upgrade...  :-[ :-\ :'(
Title: Re: Confirmed bug: HFS doesn't discard previous auth sessions
Post by: Mars on May 04, 2020, 08:37:18 AM
hslib.pas , substitute 'WWW-Auth........'  text will remove request of ident
Title: Re: Confirmed bug: HFS doesn't discard previous auth sessions
Post by: LeoNeeson on May 05, 2020, 05:30:25 AM
hslib.pas , substitute 'WWW-Auth........'  text will remove request of ident
@Mars: I appreciate your comment. Your suggestion is only a detail, not as important as having a proper logout (we are talking about having a logout that actually works when we use a form-based login, something completely different to the login process).

;D :P ...but if you want to talk about this, I will comment my idea. Instead of removing the login request (like you suggest), I've found here (https://stackoverflow.com/a/20221330) a much better solution. It consist of the server NOT giving the reply 'WWW-Authenticate' when the client send THIS on the header: "X-Requested-With: XMLHttpRequest". That way we keep everything according the standards (and we don't break the normal function).

Currently, we have something like this (on main.pas):

Code: [Select]
.......
    if result then exit;
    conn.reply.realm:=f.getShownRealm();
    runEventScript('unauthorized');
    getPage('unauthorized', data);
    // log anyone trying to guess the password
    if (forceFile = NIL) and stringExists(data.usr, getAccountList(TRUE, FALSE))
    and logOtherEventsChk.checked then
      add2log('Login failed', data);
    end; // accessGranted
.......

With the new changes I propose, it will be something like this (my additions are marked in blue color):

Quote
.......
    if result then exit;
    if (conn.getHeader('X-Requested-With') = 'XMLHttpRequest') then //add by leo
        getPage('unauthorized', data); //add by leo
    else //add by leo
        conn.reply.realm:=f.getShownRealm();
        runEventScript('unauthorized');
        getPage('unauthorized', data);
    end; //add by leo
    // log anyone trying to guess the password
    if (forceFile = NIL) and stringExists(data.usr, getAccountList(TRUE, FALSE))
    and logOtherEventsChk.checked then
      add2log('Login failed', data);
    end; // accessGranted
.......

(The code above is untested, but that's the main idea).

Mars: besides that, and talking again about the logout, feel free to ask if you don't understand something or if you can't reproduce it, following my steps. If you need, I can post any of my previous posts on french language (using a translator), but I guess it will be worst, since online translators are not good. Your english is good, but in case of doubt, perhaps SilentPliz can explain to you this better than me (in french).

Vouloir c’est pouvoir. :) ;)
Title: Re: Bug: Logout function at server level
Post by: rejetto on May 09, 2020, 05:37:12 PM
sorry i totally missed this topic, i'm reading now
Title: Re: Bug: Logout function at server level
Post by: rejetto on May 09, 2020, 06:22:30 PM
you made a wonderful work Leo, thanks :)
i'm now following your suggestion for a better fix removing the whole session.
Have to study it a bit because it's old stuff i don't remember.
Title: Re: Bug: Logout function at server level
Post by: rejetto on May 09, 2020, 08:08:31 PM
ok, i think this should be a solution
Code: [Select]
procedure TconnData.logout();
begin
freeAndNIL(session);
sessions.delete(sessions.IndexOf(sessionID));
sessionID:='';
usr:='';
pwd:='';
conn.delCookie(SESSION_COOKIE);
end; // logout
Title: Re: Bug: Logout function at server level
Post by: rejetto on May 09, 2020, 09:37:56 PM
i'm also taking care of the problem that sessions never expire
Title: Re: Bug: Logout function at server level
Post by: rejetto on May 09, 2020, 10:21:29 PM
please have a look
https://github.com/rejetto/hfs2/releases/tag/v2.4-alpha05
Title: Logout function at server level [Fixed]
Post by: LeoNeeson on May 10, 2020, 12:38:37 AM
WOW!! Now you fixed it!!! (https://i.imgur.com/Rr0Mejs.gif)
(Edit: there is a very small issue still present)

you made a wonderful work Leo, thanks :)
You welcome, my fixes were nothing compared to your awesome work. :D  (your logout implementation is fantastic, since you have covered a lot of details). For me, we could give this issue as concluded. :)



» Edit #1: I've found a super-small detail that you don't need to fix if it's complicated (please read edit #2 to know how to reproduce it). If the user is fast enough, and goes back (or if he had another tabs open) and try to access another couple of protected files (a few seconds after logout), then he could open a few protected files more. This only happens for a few seconds after doing the logout (since if connections get closed by timeout, then he could not regain access to any other protected file). That's why I added a line to "kick idle connections" (but I didn't like to do it, because it could kick an important idle connection from other users). Possible solution to this? Perhaps if an 'extra check' is done on every file request (at least, only for a few seconds after logout was called), or even better, if we could kick idle connections but only from the recently logged-out user, then this would be absolutely 100% perfect. But hey! it's 99.9999% perfect, so, don't take this as a request (it's only a super-ultra-small detail), since for me this is completely solved. :)



» Edit #2: How to reproduce this small issue?: open several pass-protected pictures (on different tabs, let say: pic1.jpg, pic2.jpg and pic3.jpg), then click on logout, and then quickly go back and click on another pass-protected picture (one that was not previously cached, like pic4.jpg), ...and bang! pic4.jpg is just loaded fine (and it shouldn't be loaded at this point, because we have logged out). This happens meanwhile some idle connection of pic1.jpg, pic2.jpg or pic3.jpg is still active (when those idle connections timeout, then everything works as expected and you can't access any other pass-protected file). And yes, I've tested this using v2.4 Alpha 5 (https://github.com/rejetto/hfs2/releases/download/v2.4-alpha05/hfs24pre05.exe), 6 (https://github.com/rejetto/hfs2/releases/download/v2.4-alpha06/hfs24pre06.exe) & 7 (https://github.com/rejetto/hfs2/releases/download/v2.4-alpha07/hfs24pre07.exe), and the issue is still present. If 'somehow' we can 'accelerate' the closing of those idle connections, then this would be just perfect. 8)



Cheers,
Leo.-
 
Title: Re: Bug: Logout function at server level [Fixed]
Post by: rejetto on May 10, 2020, 08:02:07 AM
there is a flaw in the way you produce the problem: clicking is not enough, the logout is to be considered completed when you receive the answer from the server.

also, are you using the alpha 5 for your tests? because it contains more changes to the code i published  above, and the logout is also removing this session from all active connections, immediately.
See at https://github.com/rejetto/hfs2/commit/82de2130592f2c4ee5b832a17c5c6b7b059995ec
Title: Re: Bug: Logout function at server level [Fixed]
Post by: SilentPliz on May 10, 2020, 09:18:18 AM

Thank you Leo for being one of the only people who thought that logging out was possible with HFS, and for working to lay the groundwork for a viable solution.

Thank you rejetto for your expert and complete implementation in the HFS code.

It's a good day today, I think! :) ;)
Title: Re: Bug: Logout function at server level [Fixed]
Post by: rejetto on May 10, 2020, 01:24:25 PM
i just updated the documentation for diff template, and you may be interested that it is possible to enter the path to an external file where you keep the diff template
Title: Re: Bug: Logout function at server level [Fixed]
Post by: SilentPliz on May 10, 2020, 01:56:13 PM
i just updated the documentation for diff template, and you may be interested that it is possible to enter the path to an external file where you keep the diff template


Héhéhé !!!  :-*

Title: Re: Bug: Logout function at server level [Fixed]
Post by: Mars on May 10, 2020, 02:35:28 PM

Quote from: silentpliz
Mars, arrête de pirater mes posts, sinon je me fâche !!!

 Finally Silentpliz found his electric razor  8)
before (http://rejetto.com/forum/index.php?action=dlattach;attach=9925;type=avatar)

and after (https://i27.servimg.com/u/f27/16/40/25/39/avatar10.png)

by its star rating we can see that its neurons are 100% charged again  ;D ;D


Title: Re: Bug: Logout function at server level [Fixed]
Post by: SilentPliz on May 11, 2020, 09:37:43 PM
i just updated the documentation for diff template, and you may be interested that it is possible to enter the path to an external file where you keep the diff template
Tested today... I like that feature.  8) 
Thanks rejetto.
Title: Re: Logout function at server level [almost completed]
Post by: LeoNeeson on May 12, 2020, 04:00:26 AM
i just updated the documentation for diff template, and you may be interested that it is possible to enter the path to an external file where you keep the diff template
Tested today... I like that feature.  8) 
Thanks rejetto.
Yes, it comes very handy, thanks! :)

Text taken from the wiki: "Diff template (https://www.rejetto.com/wiki/index.php?title=HFS:_Virtual_File_System_menu): If you prefer you can keep the text in a file, and enter in this box just the path of the file." One question: I haven't thoroughly tested, but I guess it also support relative paths, and the file can have any name and extension besides "hfs.diff.tpl", right?. Can it be .\TempDiff.txt (and will it work)?...
Title: Re: Logout function at server level [almost completed]
Post by: LeoNeeson on May 12, 2020, 04:02:46 AM
there is a flaw in the way you produce the problem: clicking is not enough, the logout is to be considered completed when you receive the answer from the server.
"clicking is not enough (https://i2.wp.com/www.newsfromthecouch.com/wp-content/uploads/2019/10/The-World-Is-Not-Enough.jpg)" (epic title for the next 007 movie!) ;D

Talking seriously, I do understand what you say, but even if you 'wait' to receive an answer from the server, this small issue continues. For example, I did this change on the template (marked in red color, and the result is the same):

Quote
function executeLogout() {
    var LogoutRealm = '__USER'+'='+'&'+'__AJAX'+'='+1;
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/');
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    if (xhr.responseText === "ok") {
                        window.location.replace('/');
                    }
                }
            }
        };
    xhr.send(LogoutRealm);
};

also, are you using the alpha 5 for your tests? because it contains more changes to the code i published  above, and the logout is also removing this session from all active connections, immediately.
See at https://github.com/rejetto/hfs2/commit/82de2130592f2c4ee5b832a17c5c6b7b059995ec
Yes, I've seen the code changes (your changes are very good and extensive), but I guess there must be something else missing (some little detail). On my proposed fix (https://rejetto.com/forum/index.php?topic=13286.msg1065529#msg1065529), that issue doesn't happen (but I think it's a little bit ugly and aggressive to 'kick all the idle connections' like I did on my fix, and I don't know if that 'kick' could affect other users in a bad way). If this issue can not be solved, I was thinking of proposing to add a macro command to 'kick all the idle connections', and send this command using the template (for those who want this to be perfect).

also, are you using the alpha 5 for your tests? because it contains more changes to the code i published  above, and the logout is also removing this session from all active connections, immediately.
Yes, I was using v2.4 Alpha 5 yesterday, and today also tried v2.4 Alpha 7 (https://github.com/rejetto/hfs2/releases/download/v2.4-alpha07/hfs24pre07.exe) (the MD5's issue was fixed on alpha 7, but this "small issue" is still present).

The 'key' to reproduce the problem is opening several tabs in your browser.

1) Install the old template (http://rejetto.com/forum/index.php?topic=13082.0) and the form-based login (http://rejetto.com/forum/index.php?topic=13054.msg1065523#msg1065523) (as usual).
2) Create one user and give that user access to a few folders (with files).
    (For example: Folder1, Folder2, Folder3, Folder4 and Folder5).
3) Login with that user, and open Folders 1 to 5, each one, on one tab.
4) Go to the tab of Folder1 (or any tab), and click on the Logout button.
5) Now go to the tab of Folder2 and click on one or more of the files there.
6) If it ask for password, click cancel and go to Folder3, Folder4 and Folder5 and try to access some of the files (during 15 to 30 seconds, you could access as many files as you want, some will fail, but some will go trough, depending on the timeout of that tab).

So, summarizing, you can continue (for at least 15 to 30 seconds), acceding to password protected files (until the last authenticated connection times out on the server). Sometimes it will ask for a password, but generally, you have 30 seconds to access some files. If you can't reproduce this, I can do a video to show this.

Cheers,
Leo.-
Title: Re: Bug: Logout function at server level [Fixed]
Post by: rejetto on May 12, 2020, 10:19:31 AM
Text taken from the wiki: "Diff template (https://www.rejetto.com/wiki/index.php?title=HFS:_Virtual_File_System_menu): If you prefer you can keep the text in a file, and enter in this box just the path of the file." One question: I haven't thoroughly tested, but I guess it also support relative paths, and the file can have any name and extension besides "hfs.diff.tpl", right?. Can it be .\TempDiff.txt (and will it work)?...

extension doesn't matter. Relative paths probably work, and are probably based on the exe path. Should test tho.
Title: Re: Bug: Logout function at server level [Fixed]
Post by: rejetto on May 12, 2020, 01:14:09 PM
Talking seriously, I do understand what you say, but even if you 'wait' to receive an answer from the server, this small issue continues. For example, I did this change on the template (marked in red color, and the result is the same):

this change you are showing here is not relevant to what i said, because it's not stopping the user from going and click other tabs before the reply arrives.
Anyway, the rest you said made it clearer to me that there is probably some problem other than "speed".
For next release I'm making a deep rewriting of the access system. I didn't try to reproduce the problem with the previous version but only with the new one, with 5 tabs, and eveything went fine. I hope that's fixed, you'll tell me.
Title: Re: Bug: Logout function at server level [Fixed]
Post by: LeoNeeson on May 13, 2020, 04:20:54 AM
I hope that's fixed, you'll tell me.
I've tested the new build [v2.4 Alpha 8 (https://github.com/rejetto/hfs2/releases/tag/v2.4-alpha08)] and I can confirm the logout is now 100% -totally and absolutely- perfect (the small issue (https://rejetto.com/forum/index.php?topic=13286.msg1065676#msg1065676) was finally solved!). Congratulations!
(https://i.imgur.com/ah8Mtea.gif)
Title: Re: Bug: Logout function at server level [Fixed]
Post by: elllectrum on April 19, 2023, 01:02:59 PM
Leo, hello!
There is a problem: If you log in locally, then the authorization form works fine, but if you access HFS from outside, via the Internet, the authorization form does not work, it does not respond to login / password. Please help me figure it out.
Title: Re: Bug: Logout function at server level [Fixed]
Post by: LeoNeeson on April 24, 2023, 10:36:26 AM
Leo, hello!
There is a problem: If you log in locally, then the authorization form works fine, but if you access HFS from outside, via the Internet, the authorization form does not work, it does not respond to login / password. Please help me figure it out.
Hi! and welcome... :)

Sorry for my late reply (I've received your private message)

Your message doesn't say what version are you using, but please make sure you use latest v2.4 (or the new HFS3). The default template of HFS v2.x depends on jQuery to work, and some older templates (based on versions older than HFS v2.3f), were using an external CDN for jQuery. Since you say it works fine locally, perhaps 'something' is blocking or interfering with the access to jQuery (and therefore, affecting the login). Sadly, I could not give you more ideas than that. I currently don't have time to deal with complex issues, but if you add much more details, perhaps we could possibly have more idea of what is causing your issue (but I cannot promise to solve it).

For as much as I would like to help people, please consider this thread closed, since it was a technical discussion to implement the logout system, which was already added on HFS 2.4. Your issue is about the login, not logout anyway (in that case, is much better open a new thread, along with more details).

Cheers,
Leo.-