<commit_before>package apps

import (
	"bytes"
	"html/template"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"time"

	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/sessions"
	"github.com/cozy/cozy-stack/pkg/vfs"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/labstack/echo"
	"github.com/spf13/afero"
)

// Serve is an handler for serving files from the VFS for a client-side app
func Serve(c echo.Context) error {
	method := c.Request().Method
	if method != "GET" && method != "HEAD" {
		return echo.NewHTTPError(http.StatusMethodNotAllowed, "Method %s not allowed", method)
	}
	i := middlewares.GetInstance(c)
	if config.GetConfig().Subdomains == config.FlatSubdomains {
		if code := c.QueryParam("code"); code != "" {
			return tryAuthWithSessionCode(c, i, code)
		}
	}
	slug := c.Get("slug").(string)
	app, err := apps.GetWebappBySlug(i, slug)
	if err != nil {
		if couchdb.IsNotFoundError(err) {
			return echo.NewHTTPError(http.StatusNotFound, "Application not found")
		}
		return err
	}
	if app.State() != apps.Ready {
		return echo.NewHTTPError(http.StatusServiceUnavailable, "Application is not ready")
	}
	return ServeAppFile(c, i, NewServer(i.VFS()), app)
}

// ServeAppFile will serve the requested file using the specified application
// manifest and AppFileServer context.
//
// It can be used to serve file application in another context than the VFS,
// for instance for tests or development puposes where we want to serve an
// application that is not installed on the user's instance. However this
// procedure should not be used for standard applications, use the Serve method
// for that.
func ServeAppFile(c echo.Context, i *instance.Instance, fs AppFileServer, app *apps.WebappManifest) error {
	slug := app.Slug()
	route, file := app.FindRoute(path.Clean(c.Request().URL.Path))
	if route.NotFound() {
		return echo.NewHTTPError(http.StatusNotFound, "Page not found")
	}
	if !route.Public && !middlewares.IsLoggedIn(c) {
		if file != "" {
			return echo.NewHTTPError(http.StatusUnauthorized, "You must be authenticated")
		}
		subdomain := i.SubDomain(slug)
		subdomain.Path = c.Request().URL.String()
		redirect := url.Values{
			"redirect": {subdomain.String()},
		}
		return c.Redirect(http.StatusFound, i.PageURL("/auth/login", redirect))
	}
	if file == "" {
		file = route.Index
	}
	infos, err := fs.Stat(slug, route.Folder, file)
	if os.IsNotExist(err) {
		return echo.NewHTTPError(http.StatusNotFound)
	}<commit_msg>Fix session issue with onboarding and flat subdomains<commit_after>package apps

import (
	"bytes"
	"html/template"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path"
	"time"

	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/sessions"
	"github.com/cozy/cozy-stack/pkg/vfs"
	"github.com/cozy/cozy-stack/web/middlewares"
	"github.com/labstack/echo"
	"github.com/spf13/afero"
)

// Serve is an handler for serving files from the VFS for a client-side app
func Serve(c echo.Context) error {
	method := c.Request().Method
	if method != "GET" && method != "HEAD" {
		return echo.NewHTTPError(http.StatusMethodNotAllowed, "Method %s not allowed", method)
	}
	i := middlewares.GetInstance(c)
	if config.GetConfig().Subdomains == config.FlatSubdomains {
		if code := c.QueryParam("code"); code != "" {
			return tryAuthWithSessionCode(c, i, code)
		}
	}
	slug := c.Get("slug").(string)
	app, err := apps.GetWebappBySlug(i, slug)
	if err != nil {
		if couchdb.IsNotFoundError(err) {
			return echo.NewHTTPError(http.StatusNotFound, "Application not found")
		}
		return err
	}
	if app.State() != apps.Ready {
		return echo.NewHTTPError(http.StatusServiceUnavailable, "Application is not ready")
	}
	return ServeAppFile(c, i, NewServer(i.VFS()), app)
}

func onboarding(c echo.Context) bool {
	i := middlewares.GetInstance(c)
	if len(i.RegisterToken) == 0 {
		return false
	}
	return c.QueryParam("registerToken") != ""
}

// ServeAppFile will serve the requested file using the specified application
// manifest and AppFileServer context.
//
// It can be used to serve file application in another context than the VFS,
// for instance for tests or development puposes where we want to serve an
// application that is not installed on the user's instance. However this
// procedure should not be used for standard applications, use the Serve method
// for that.
func ServeAppFile(c echo.Context, i *instance.Instance, fs AppFileServer, app *apps.WebappManifest) error {
	slug := app.Slug()
	route, file := app.FindRoute(path.Clean(c.Request().URL.Path))
	if route.NotFound() {
		return echo.NewHTTPError(http.StatusNotFound, "Page not found")
	}
	needAuth := !route.Public
	if slug == consts.OnboardingSlug && file == "" && !onboarding(c) {
		needAuth = true
	}
	if needAuth && !middlewares.IsLoggedIn(c) {
		if file != "" {
			return echo.NewHTTPError(http.StatusUnauthorized, "You must be authenticated")
		}
		subdomain := i.SubDomain(slug)
		subdomain.Path = c.Request().URL.String()
		redirect := url.Values{
			"redirect": {subdomain.String()},
		}
		return c.Redirect(http.StatusFound, i.PageURL("/auth/login", redirect))
	}
	if file == "" {
		file = route.Index
	}
	infos, err := fs.Stat(slug, route.Folder, file)
	if os.IsNotExist(err) {
		return echo.NewHTTPError(http.StatusNotFound)
	}
{'fraction_non_alphanumeric': 0.14233064233064233, 'fraction_numerical': 0.0008775008775008775, 'mean_word_length': 4.199817518248175, 'pattern_counts': {'":': 2, '<': 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': '6914509', 'n_tokens_mistral': 2082, 'n_tokens_neox': 2033, 'n_words': 477}