// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package dash

import (
	"errors"
	"fmt"
	"net/http"
	"strings"

	"golang.org/x/net/context"
	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/user"
)

type AccessLevel int

const (
	AccessPublic AccessLevel = iota + 1
	AccessUser
	AccessAdmin
)

func verifyAccessLevel(access AccessLevel) {
	switch access {
	case AccessPublic, AccessUser, AccessAdmin:
		return
	default:
		panic(fmt.Sprintf("bad access level %v", access))
	}
}

var ErrAccess = errors.New("unauthorized")

func checkAccessLevel(c context.Context, r *http.Request, level AccessLevel) error {
	if accessLevel(c, r) >= level {
		return nil
	}
	if u := user.Current(c); u != nil {
		// Log only if user is signed in. Not-signed-in users are redirected to login page.
		log.Errorf(c, "unauthorized access: %q [%q] access level %v", u.Email, u.AuthDomain, level)
	}
	return ErrAccess
}

func accessLevel(c context.Context, r *http.Request) AccessLevel {
	if user.IsAdmin(c) {
		switch r.FormValue("access") {
		case "public":
			return AccessPublic
		case "user":
			return AccessUser
		}
		return AccessAdmin
	}
	u := user.Current(c)
	if u == nil ||
		// devappserver is broken
		u.AuthDomain != "gmail.com" && !appengine.IsDevAppServer() ||
		!strings.HasSuffix(u.Email, config.AuthDomain) {
		return AccessPublic
	}
	return AccessUser
}

func checkTextAccess(c context.Context, r *http.Request, tag string, id int64) (*Crash, error) {
	switch tag {
	default:
		return nil, checkAccessLevel(c, r, AccessAdmin)
	case textPatch:
		return nil, checkJobTextAccess(c, r, "Patch", id)
	case textError:
		return nil, checkJobTextAccess(c, r, "Error", id)
	case textKernelConfig:
		// This is checked based on text namespace.
		return nil, nil
	case textCrashLog:
		// Log and Report can be attached to a Crash or Job.
		crash, err := checkCrashTextAccess(c, r, "Log", id)
		if err == nil || err == ErrAccess {
			return crash, err
		}
		return nil, checkJobTextAccess(c, r, "CrashLog", id)
	case textCrashReport:
		crash, err := checkCrashTextAccess(c, r, "Report", id)
		if err == nil || err == ErrAccess {
			return crash, err
		}
		return nil, checkJobTextAccess(c, r, "CrashReport", id)
	case textReproSyz:
		return checkCrashTextAccess(c, r, "ReproSyz", id)
	case textReproC:
		return checkCrashTextAccess(c, r, "ReproC", id)
	}
}

func checkCrashTextAccess(c context.Context, r *http.Request, field string, id int64) (*Crash, error) {
	var crashes []*Crash
	keys, err := datastore.NewQuery("Crash").
		Filter(field+"=", id).
		GetAll(c, &crashes)
	if err != nil {
		return nil, fmt.Errorf("failed to query crashes: %v", err)
	}
	if len(crashes) != 1 {
		return nil, fmt.Errorf("checkCrashTextAccess: found %v crashes for %v=%v",
			len(crashes), field, id)
	}
	crash := crashes[0]
	bug := new(Bug)
	if err := datastore.Get(c, keys[0].Parent(), bug); err != nil {
		return nil, fmt.Errorf("failed to get bug: %v", err)
	}
	bugLevel := bug.sanitizeAccess(accessLevel(c, r))
	return crash, checkAccessLevel(c, r, bugLevel)
}

func checkJobTextAccess(c context.Context, r *http.Request, field string, id int64) error {
	keys, err := datastore.NewQuery("Job").
		Filter(field+"=", id).
		KeysOnly().
		GetAll(c, nil)
	if err != nil {
		return fmt.Errorf("failed to query jobs: %v", err)
	}
	if len(keys) != 1 {
		return fmt.Errorf("checkJobTextAccess: found %v jobs for %v=%v",
			len(keys), field, id)
	}
	bug := new(Bug)
	if err := datastore.Get(c, keys[0].Parent(), bug); err != nil {
		return fmt.Errorf("failed to get bug: %v", err)
	}
	bugLevel := bug.sanitizeAccess(accessLevel(c, r))
	return checkAccessLevel(c, r, bugLevel)
}

func (bug *Bug) sanitizeAccess(currentLevel AccessLevel) AccessLevel {
	for ri := len(bug.Reporting) - 1; ri >= 0; ri-- {
		bugReporting := &bug.Reporting[ri]
		if ri == 0 || !bugReporting.Reported.IsZero() {
			ns := config.Namespaces[bug.Namespace]
			bugLevel := ns.ReportingByName(bugReporting.Name).AccessLevel
			if currentLevel < bugLevel {
				if bug.Status == BugStatusFixed || len(bug.Commits) != 0 {
					// Fixed bugs are visible in all reportings,
					// however, without previous reporting private information.
					lastLevel := ns.Reporting[len(ns.Reporting)-1].AccessLevel
					if currentLevel >= lastLevel {
						bugLevel = lastLevel
						sanitizeReporting(bug)
					}
				}
			}
			return bugLevel
		}
	}
	panic("unreachable")
}

func sanitizeReporting(bug *Bug) {
	bug.DupOf = ""
	for ri := range bug.Reporting {
		bugReporting := &bug.Reporting[ri]
		bugReporting.ID = ""
		bugReporting.ExtID = ""
		bugReporting.Link = ""
	}
}
