1// Copyright 2011 Google Inc. All rights reserved.
2// Use of this source code is governed by the Apache 2.0
3// license that can be found in the LICENSE file.
4
5package appengine
6
7import (
8	"time"
9
10	"golang.org/x/net/context"
11
12	"google.golang.org/appengine/internal"
13	pb "google.golang.org/appengine/internal/app_identity"
14	modpb "google.golang.org/appengine/internal/modules"
15)
16
17// AppID returns the application ID for the current application.
18// The string will be a plain application ID (e.g. "appid"), with a
19// domain prefix for custom domain deployments (e.g. "example.com:appid").
20func AppID(c context.Context) string { return internal.AppID(c) }
21
22// DefaultVersionHostname returns the standard hostname of the default version
23// of the current application (e.g. "my-app.appspot.com"). This is suitable for
24// use in constructing URLs.
25func DefaultVersionHostname(c context.Context) string {
26	return internal.DefaultVersionHostname(c)
27}
28
29// ModuleName returns the module name of the current instance.
30func ModuleName(c context.Context) string {
31	return internal.ModuleName(c)
32}
33
34// ModuleHostname returns a hostname of a module instance.
35// If module is the empty string, it refers to the module of the current instance.
36// If version is empty, it refers to the version of the current instance if valid,
37// or the default version of the module of the current instance.
38// If instance is empty, ModuleHostname returns the load-balancing hostname.
39func ModuleHostname(c context.Context, module, version, instance string) (string, error) {
40	req := &modpb.GetHostnameRequest{}
41	if module != "" {
42		req.Module = &module
43	}
44	if version != "" {
45		req.Version = &version
46	}
47	if instance != "" {
48		req.Instance = &instance
49	}
50	res := &modpb.GetHostnameResponse{}
51	if err := internal.Call(c, "modules", "GetHostname", req, res); err != nil {
52		return "", err
53	}
54	return *res.Hostname, nil
55}
56
57// VersionID returns the version ID for the current application.
58// It will be of the form "X.Y", where X is specified in app.yaml,
59// and Y is a number generated when each version of the app is uploaded.
60// It does not include a module name.
61func VersionID(c context.Context) string { return internal.VersionID(c) }
62
63// InstanceID returns a mostly-unique identifier for this instance.
64func InstanceID() string { return internal.InstanceID() }
65
66// Datacenter returns an identifier for the datacenter that the instance is running in.
67func Datacenter(c context.Context) string { return internal.Datacenter(c) }
68
69// ServerSoftware returns the App Engine release version.
70// In production, it looks like "Google App Engine/X.Y.Z".
71// In the development appserver, it looks like "Development/X.Y".
72func ServerSoftware() string { return internal.ServerSoftware() }
73
74// RequestID returns a string that uniquely identifies the request.
75func RequestID(c context.Context) string { return internal.RequestID(c) }
76
77// AccessToken generates an OAuth2 access token for the specified scopes on
78// behalf of service account of this application. This token will expire after
79// the returned time.
80func AccessToken(c context.Context, scopes ...string) (token string, expiry time.Time, err error) {
81	req := &pb.GetAccessTokenRequest{Scope: scopes}
82	res := &pb.GetAccessTokenResponse{}
83
84	err = internal.Call(c, "app_identity_service", "GetAccessToken", req, res)
85	if err != nil {
86		return "", time.Time{}, err
87	}
88	return res.GetAccessToken(), time.Unix(res.GetExpirationTime(), 0), nil
89}
90
91// Certificate represents a public certificate for the app.
92type Certificate struct {
93	KeyName string
94	Data    []byte // PEM-encoded X.509 certificate
95}
96
97// PublicCertificates retrieves the public certificates for the app.
98// They can be used to verify a signature returned by SignBytes.
99func PublicCertificates(c context.Context) ([]Certificate, error) {
100	req := &pb.GetPublicCertificateForAppRequest{}
101	res := &pb.GetPublicCertificateForAppResponse{}
102	if err := internal.Call(c, "app_identity_service", "GetPublicCertificatesForApp", req, res); err != nil {
103		return nil, err
104	}
105	var cs []Certificate
106	for _, pc := range res.PublicCertificateList {
107		cs = append(cs, Certificate{
108			KeyName: pc.GetKeyName(),
109			Data:    []byte(pc.GetX509CertificatePem()),
110		})
111	}
112	return cs, nil
113}
114
115// ServiceAccount returns a string representing the service account name, in
116// the form of an email address (typically app_id@appspot.gserviceaccount.com).
117func ServiceAccount(c context.Context) (string, error) {
118	req := &pb.GetServiceAccountNameRequest{}
119	res := &pb.GetServiceAccountNameResponse{}
120
121	err := internal.Call(c, "app_identity_service", "GetServiceAccountName", req, res)
122	if err != nil {
123		return "", err
124	}
125	return res.GetServiceAccountName(), err
126}
127
128// SignBytes signs bytes using a private key unique to your application.
129func SignBytes(c context.Context, bytes []byte) (keyName string, signature []byte, err error) {
130	req := &pb.SignForAppRequest{BytesToSign: bytes}
131	res := &pb.SignForAppResponse{}
132
133	if err := internal.Call(c, "app_identity_service", "SignForApp", req, res); err != nil {
134		return "", nil, err
135	}
136	return res.GetKeyName(), res.GetSignatureBytes(), nil
137}
138
139func init() {
140	internal.RegisterErrorCodeMap("app_identity_service", pb.AppIdentityServiceError_ErrorCode_name)
141	internal.RegisterErrorCodeMap("modules", modpb.ModulesServiceError_ErrorCode_name)
142}
143