<commit_before>// Package auth provides register and login handlers
package auth

import (
	"crypto/subtle"
	"net/http"
	"net/url"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/sessions"
	"github.com/cozy/cozy-stack/web/middlewares"
	webpermissions "github.com/cozy/cozy-stack/web/permissions"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

// With the nested subdomains structure, the cookie set on the main domain can
// also be used to authentify the user on the apps subdomain. But with the flat
// subdomains structure, a new cookie is needed. To transfer the session, we
// add a code parameter to the redirect URL that can be exchanged to the
// cookie. The code can be used only once, is valid only one minute, and is
// specific to the app (it can't be used by another app).
func addCodeToRedirect(redirect, domain, sessionID string) string {
	// TODO add rate-limiting on the number of session codes generated
	if config.GetConfig().Subdomains == config.FlatSubdomains {
		u, err := url.Parse(redirect)
		if err == nil && u.Host != domain {
			q := u.Query()
			q.Set("code", sessions.BuildCode(sessionID, u.Host).Value)
			u.RawQuery = q.Encode()
			return u.String()
		}
	}
	return redirect
}

// SetCookieForNewSession creates a new session and sets the cookie on echo context
func SetCookieForNewSession(c echo.Context) (string, error) {
	instance := middlewares.GetInstance(c)

	session, err := sessions.New(instance)
	if err != nil {
		return "", err
	}
	cookie, err := session.ToCookie()
	if err != nil {
		return "", err
	}
	c.SetCookie(cookie)
	return session.ID(), nil
}

// redirectSuccessLogin sends a redirection to the browser after a successful login
func redirectSuccessLogin(c echo.Context, redirect string) error {
	sessID, err := SetCookieForNewSession(c)
	if err != nil {
		return err
	}

	instance := middlewares.GetInstance(c)
	redirect = addCodeToRedirect(redirect, instance.Domain, sessID)
	return c.Redirect(http.StatusSeeOther, redirect)
}

func loginForm(c echo.Context) error {
	instance := middlewares.GetInstance(c)

	redirect, err := checkRedirectParam(c, instance.SubDomain(apps.HomeSlug))
	if err != nil {
		return err
	}

	session, err := sessions.GetSession(c, instance)
	if err == nil {
		redirect = addCodeToRedirect(redirect, instance.Domain, session.ID())
		return c.Redirect(http.StatusSeeOther, redirect)
	}

	return c.Render(http.StatusOK, "login.html", echo.Map{
		"InvalidPassphrase": false,
		"Redirect":          redirect,
	})
}

func login(c echo.Context) error {
	instance := middlewares.GetInstance(c)

	redirect, err := checkRedirectParam(c, instance.SubDomain(apps.HomeSlug))
	if err != nil {
		return err
	}

	session, err := sessions.GetSession(c, instance)
	if err == nil {
		redirect = addCodeToRedirect(redirect, instance.Domain, session.ID())
		return c.Redirect(http.StatusSeeOther, redirect)
	}

	passphrase := []byte(c.FormValue("passphrase"))
	if err := instance.CheckPassphrase(passphrase); err == nil {<commit_msg>[feat] Tries to retrieves public name in login page<commit_after>// Package auth provides register and login handlers
package auth

import (
	"crypto/subtle"
	"net/http"
	"net/url"
	"strings"

	log "github.com/Sirupsen/logrus"
	"github.com/cozy/cozy-stack/pkg/apps"
	"github.com/cozy/cozy-stack/pkg/config"
	"github.com/cozy/cozy-stack/pkg/consts"
	"github.com/cozy/cozy-stack/pkg/couchdb"
	"github.com/cozy/cozy-stack/pkg/instance"
	"github.com/cozy/cozy-stack/pkg/oauth"
	"github.com/cozy/cozy-stack/pkg/permissions"
	"github.com/cozy/cozy-stack/pkg/sessions"
	"github.com/cozy/cozy-stack/web/middlewares"
	webpermissions "github.com/cozy/cozy-stack/web/permissions"
	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

// With the nested subdomains structure, the cookie set on the main domain can
// also be used to authentify the user on the apps subdomain. But with the flat
// subdomains structure, a new cookie is needed. To transfer the session, we
// add a code parameter to the redirect URL that can be exchanged to the
// cookie. The code can be used only once, is valid only one minute, and is
// specific to the app (it can't be used by another app).
func addCodeToRedirect(redirect, domain, sessionID string) string {
	// TODO add rate-limiting on the number of session codes generated
	if config.GetConfig().Subdomains == config.FlatSubdomains {
		u, err := url.Parse(redirect)
		if err == nil && u.Host != domain {
			q := u.Query()
			q.Set("code", sessions.BuildCode(sessionID, u.Host).Value)
			u.RawQuery = q.Encode()
			return u.String()
		}
	}
	return redirect
}

// SetCookieForNewSession creates a new session and sets the cookie on echo context
func SetCookieForNewSession(c echo.Context) (string, error) {
	instance := middlewares.GetInstance(c)

	session, err := sessions.New(instance)
	if err != nil {
		return "", err
	}
	cookie, err := session.ToCookie()
	if err != nil {
		return "", err
	}
	c.SetCookie(cookie)
	return session.ID(), nil
}

// redirectSuccessLogin sends a redirection to the browser after a successful login
func redirectSuccessLogin(c echo.Context, redirect string) error {
	sessID, err := SetCookieForNewSession(c)
	if err != nil {
		return err
	}

	instance := middlewares.GetInstance(c)
	redirect = addCodeToRedirect(redirect, instance.Domain, sessID)
	return c.Redirect(http.StatusSeeOther, redirect)
}

func loginForm(c echo.Context) error {
	instance := middlewares.GetInstance(c)

	redirect, err := checkRedirectParam(c, instance.SubDomain(apps.HomeSlug))
	if err != nil {
		return err
	}

	session, err := sessions.GetSession(c, instance)
	if err == nil {
		redirect = addCodeToRedirect(redirect, instance.Domain, session.ID())
		return c.Redirect(http.StatusSeeOther, redirect)
	}

	doc := &couchdb.JSONDoc{}
	err = couchdb.GetDoc(instance, consts.Settings, consts.InstanceSettingsID, doc)
	if err != nil {
		return err
	}

	publicName, ok := doc.M["public_name"].(string)

	if !ok {
		publicName = ""
	}

	return c.Render(http.StatusOK, "login.html", echo.Map{
		"PublicName":        publicName,
		"InvalidPassphrase": false,
		"Redirect":          redirect,
	})
}

func login(c echo.Context) error {
	instance := middlewares.GetInstance(c)

	redirect, err := checkRedirectParam(c, instance.SubDomain(apps.HomeSlug))
	if err != nil {
		return err
	}

	session, err := sessions.GetSession(c, instance)
	if err == nil {
		redirect = addCodeToRedirect(redirect, instance.Domain, session.ID())
		return c.Redirect(http.StatusSeeOther, redirect)
	}

	passphrase := []byte(c.FormValue("passphrase"))
	if err := instance.CheckPassphrase(passphrase); err == nil {
{'fraction_non_alphanumeric': 0.12487440792306588, 'fraction_numerical': 0.0, 'mean_word_length': 4.246987951807229, 'pattern_counts': {'":': 5, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '460516', 'n_tokens_mistral': 2382, 'n_tokens_neox': 2296, 'n_words': 616}