/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package alts

import (
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"regexp"
	"runtime"
	"strings"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/peer"
	"google.golang.org/grpc/status"
)

const (
	linuxProductNameFile     = "/sys/class/dmi/id/product_name"
	windowsCheckCommand      = "powershell.exe"
	windowsCheckCommandArgs  = "Get-WmiObject -Class Win32_BIOS"
	powershellOutputFilter   = "Manufacturer"
	windowsManufacturerRegex = ":(.*)"
)

type platformError string

func (k platformError) Error() string {
	return fmt.Sprintf("%s is not supported", string(k))
}

var (
	// The following two variables will be reassigned in tests.
	runningOS          = runtime.GOOS
	manufacturerReader = func() (io.Reader, error) {
		switch runningOS {
		case "linux":
			return os.Open(linuxProductNameFile)
		case "windows":
			cmd := exec.Command(windowsCheckCommand, windowsCheckCommandArgs)
			out, err := cmd.Output()
			if err != nil {
				return nil, err
			}

			for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
				if strings.HasPrefix(line, powershellOutputFilter) {
					re := regexp.MustCompile(windowsManufacturerRegex)
					name := re.FindString(line)
					name = strings.TrimLeft(name, ":")
					return strings.NewReader(name), nil
				}
			}

			return nil, errors.New("cannot determine the machine's manufacturer")
		default:
			return nil, platformError(runningOS)
		}
	}
	vmOnGCP bool
)

// isRunningOnGCP checks whether the local system, without doing a network request is
// running on GCP.
func isRunningOnGCP() bool {
	manufacturer, err := readManufacturer()
	if os.IsNotExist(err) {
		return false
	}
	if err != nil {
		log.Fatalf("failure to read manufacturer information: %v", err)
	}
	name := string(manufacturer)
	switch runningOS {
	case "linux":
		name = strings.TrimSpace(name)
		return name == "Google" || name == "Google Compute Engine"
	case "windows":
		name = strings.Replace(name, " ", "", -1)
		name = strings.Replace(name, "\n", "", -1)
		name = strings.Replace(name, "\r", "", -1)
		return name == "Google"
	default:
		log.Fatal(platformError(runningOS))
	}
	return false
}

func readManufacturer() ([]byte, error) {
	reader, err := manufacturerReader()
	if err != nil {
		return nil, err
	}
	if reader == nil {
		return nil, errors.New("got nil reader")
	}
	manufacturer, err := ioutil.ReadAll(reader)
	if err != nil {
		return nil, fmt.Errorf("failed reading %v: %v", linuxProductNameFile, err)
	}
	return manufacturer, nil
}

// AuthInfoFromContext extracts the alts.AuthInfo object from the given context,
// if it exists. This API should be used by gRPC server RPC handlers to get
// information about the communicating peer. For client-side, use grpc.Peer()
// CallOption.
func AuthInfoFromContext(ctx context.Context) (AuthInfo, error) {
	p, ok := peer.FromContext(ctx)
	if !ok {
		return nil, errors.New("no Peer found in Context")
	}
	return AuthInfoFromPeer(p)
}

// AuthInfoFromPeer extracts the alts.AuthInfo object from the given peer, if it
// exists. This API should be used by gRPC clients after obtaining a peer object
// using the grpc.Peer() CallOption.
func AuthInfoFromPeer(p *peer.Peer) (AuthInfo, error) {
	altsAuthInfo, ok := p.AuthInfo.(AuthInfo)
	if !ok {
		return nil, errors.New("no alts.AuthInfo found in Peer")
	}
	return altsAuthInfo, nil
}

// ClientAuthorizationCheck checks whether the client is authorized to access
// the requested resources based on the given expected client service accounts.
// This API should be used by gRPC server RPC handlers. This API should not be
// used by clients.
func ClientAuthorizationCheck(ctx context.Context, expectedServiceAccounts []string) error {
	authInfo, err := AuthInfoFromContext(ctx)
	if err != nil {
		return status.Newf(codes.PermissionDenied, "The context is not an ALTS-compatible context: %v", err).Err()
	}
	for _, sa := range expectedServiceAccounts {
		if authInfo.PeerServiceAccount() == sa {
			return nil
		}
	}
	return status.Newf(codes.PermissionDenied, "Client %v is not authorized", authInfo.PeerServiceAccount()).Err()
}
