func createToken(ctx context.Context, channelID string) (string, error) { iss, err := appengine.ServiceAccount(ctx) if err != nil { return "", err } iat := time.Now().Unix() jwt := map[string]interface{}{ "iss": iss, "sub": iss, "aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit", "iat": iat, "exp": iat + 3600, // 1 hour "uid": channelID, } body, err := json.Marshal(jwt) if err != nil { return "", err } header := base64.StdEncoding.EncodeToString([]byte(`{"typ":"JWT","alg":"RS256"}`)) payload := append([]byte(header), byte('.')) payload = append(payload, []byte(base64.StdEncoding.EncodeToString(body))...) _, sig, err := appengine.SignBytes(ctx, payload) if err != nil { return "", err } return fmt.Sprintf("%s.%s", payload, base64.StdEncoding.EncodeToString(sig)), nil }
// Taken from http://stackoverflow.com/a/26579165/196964 and // https://cloud.google.com/storage/docs/access-control#Signed-URLs func generateSignedURLs(c context.Context, host, resource string, expiry time.Time, httpVerb, contentMD5, contentType string) (string, error) { sa, err := appengine.ServiceAccount(c) if err != nil { return "", err } expiryStr := strconv.FormatInt(expiry.Unix(), 10) // The optional components should be the empty string. // https://cloud.google.com/storage/docs/access-control#Construct-the-String components := []string{ httpVerb, // PUT, GET, DELETE (but not POST) contentMD5, // Optional. The MD5 digest value in base64. Client must provide same value if present. contentType, // Optional. Client must provide same value if present. expiryStr, // Unix timestamp resource, // /bucket/objectname } unsigned := strings.Join(components, "\n") _, b, err := appengine.SignBytes(c, []byte(unsigned)) if err != nil { return "", err } sig := base64.StdEncoding.EncodeToString(b) p := url.Values{ "GoogleAccessId": {sa}, "Expires": {expiryStr}, "Signature": {sig}, } return fmt.Sprintf("%s%s?%s", host, resource, p.Encode()), err }
func (g giImpl) ServiceAccount() (string, error) { return appengine.ServiceAccount(g.aeCtx) }