Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
09fc70b
Renamed some tests and test parameters for clarity, and adhere to Go …
hiranya911 Jan 17, 2018
c24cb17
clean unused types (#76)
avishalom Jan 19, 2018
fb6fa29
Create CHANGELOG.md (#75) (#79)
avishalom Jan 29, 2018
aae4f93
change instance ID format (#82)
avishalom Feb 1, 2018
56a7312
Import context from golang.org/x/net/ for 1.6 compatibility (#87)
avishalom Feb 8, 2018
c764f49
Document non existing name in integration tests for iid (#85)
avishalom Feb 8, 2018
06eb0e0
Revoke Tokens (#77)
avishalom Feb 13, 2018
3f7b4ba
Firebase Cloud Messaging API (#81)
hiranya911 Feb 13, 2018
82606fb
Merged with master
hiranya911 Feb 13, 2018
a053b99
Bumped version to 2.5.0 (#90)
hiranya911 Feb 14, 2018
9f91451
Merge branch 'master' into dev
hiranya911 Feb 15, 2018
0b3ac34
Merge branch 'master' into dev
hiranya911 Feb 16, 2018
fd78f9d
Lint (#96)
chemidy Feb 18, 2018
3a386a4
Doc (#97)
chemidy Feb 18, 2018
0dd57f9
Merge branch 'master' into dev
hiranya911 Feb 20, 2018
387fa39
add travis build for go versions 1.7.x -> 1.10.x (#98)
chemidy Feb 26, 2018
9d2e4a8
Import context from standard package (#101)
avishalom Feb 27, 2018
c9be1e9
Firebase Database API (#92)
hiranya911 Feb 28, 2018
3a49e80
Handling FCM canonical error codes (#103)
hiranya911 Feb 28, 2018
f03d5a6
Formatting test file with gofmt (#104)
hiranya911 Feb 28, 2018
f0be2f4
Bumped version to 2.6.0 (#105)
hiranya911 Feb 28, 2018
2331e41
Merge branch 'master' into dev
hiranya911 Feb 28, 2018
04299fa
Formatting (simplification) changes (#107)
hiranya911 Mar 1, 2018
07d3484
Checking for unformatted files in CI (#108)
hiranya911 Mar 1, 2018
0bbfc6c
Document Minimum Go Version (#111)
hiranya911 Mar 9, 2018
cf5cb07
Fix invalid endpoint URL for topic unsubscribe (#114)
michaljemala Mar 12, 2018
31b566d
Fix error message for missing user (#113)
avishalom Mar 14, 2018
a3ce7c8
Update CHANGELOG.md (#117)
hiranya911 Mar 15, 2018
9bd56f9
Removing unused member from auth.Client (#118)
hiranya911 Mar 15, 2018
0c849e9
Support Go 1.6 (#120)
tbpg Mar 15, 2018
eae7451
Bumped version to 2.6.1 (#121)
avishalom Mar 15, 2018
98f50a2
Changlog updates (#123)
avishalom Mar 15, 2018
1ad967f
Merge branch 'master' into dev
hiranya911 Mar 15, 2018
201a4f3
Reading FCM error code from details section (#127)
hiranya911 Mar 30, 2018
6cf2210
Adding additional details to the error message when available (#129)
hiranya911 Apr 4, 2018
1b20f5a
Implementing support for APNS content-mutable field (#126)
hiranya911 Apr 6, 2018
0beafb8
Implementing Functions to Test Error Codes (#131)
hiranya911 Apr 10, 2018
bb41405
Add Go import comments. (#132)
functionary Apr 11, 2018
0dd6a00
Bumped version to 2.7.0 (#133)
hiranya911 Apr 17, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Unreleased

-

# v2.7.0

- [added] Added several new functions for testing errors
(e.g. `auth.IsUserNotFound()`).
- [added] Added support for setting the `mutable-content` property on
FCM messages sent via APNS.
- [changed] Updated the error messages returned by the `messaging`
package. These errors now contain the full details sent by the
back-end server.

# v2.6.1

- [added] Added support for Go 1.6.
Expand Down
2 changes: 1 addition & 1 deletion auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func (c *Client) VerifyIDTokenAndCheckRevoked(ctx context.Context, idToken strin
}

if p.IssuedAt*1000 < user.TokensValidAfterMillis {
return nil, fmt.Errorf("ID token has been revoked")
return nil, internal.Error(idTokenRevoked, "ID token has been revoked")
}
return p, nil
}
Expand Down
2 changes: 1 addition & 1 deletion auth/auth_std.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package auth
package auth // import "firebase.google.com/go/auth"

import "golang.org/x/net/context"

Expand Down
2 changes: 1 addition & 1 deletion auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ func TestVerifyIDTokenAndCheckRevokedInvalidated(t *testing.T) {

p, err := s.Client.VerifyIDTokenAndCheckRevoked(ctx, tok)
we := "ID token has been revoked"
if p != nil || err == nil || err.Error() != we {
if p != nil || err == nil || err.Error() != we || !IsIDTokenRevoked(err) {
t.Errorf("VerifyIDTokenAndCheckRevoked(ctx, token) =(%v, %v); want = (%v, %v)",
p, err, nil, we)
}
Expand Down
116 changes: 101 additions & 15 deletions auth/user_mgt.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ import (
"strings"
"time"

"firebase.google.com/go/internal"
"golang.org/x/net/context"

"google.golang.org/api/googleapi"
"google.golang.org/api/identitytoolkit/v3"
"google.golang.org/api/iterator"
)
Expand Down Expand Up @@ -215,8 +217,10 @@ func (c *Client) DeleteUser(ctx context.Context, uid string) error {

call := c.is.Relyingparty.DeleteAccount(request)
c.setHeader(call)
_, err := call.Context(ctx).Do()
return err
if _, err := call.Context(ctx).Do(); err != nil {
return handleServerError(err)
}
return nil
}

// GetUser gets the user data corresponding to the specified user ID.
Expand Down Expand Up @@ -279,7 +283,7 @@ func (it *UserIterator) fetch(pageSize int, pageToken string) (string, error) {
it.client.setHeader(call)
resp, err := call.Context(it.ctx).Do()
if err != nil {
return "", err
return "", handleServerError(err)
}

for _, u := range resp.Users {
Expand Down Expand Up @@ -345,10 +349,7 @@ func processClaims(p map[string]interface{}) error {
return nil
}

claims, ok := cc.(map[string]interface{})
if !ok {
return fmt.Errorf("unexpected type for custom claims")
}
claims := cc.(map[string]interface{})
for _, key := range reservedClaims {
if _, ok := claims[key]; ok {
return fmt.Errorf("claim %q is reserved and must not be set", key)
Expand All @@ -372,6 +373,83 @@ func processClaims(p map[string]interface{}) error {
return nil
}

// Error handlers.

const (
emailAlredyExists = "email-already-exists"
idTokenRevoked = "id-token-revoked"
insufficientPermission = "insufficient-permission"
phoneNumberAlreadyExists = "phone-number-already-exists"
projectNotFound = "project-not-found"
uidAlreadyExists = "uid-already-exists"
unknown = "unknown-error"
userNotFound = "user-not-found"
)

// IsEmailAlreadyExists checks if the given error was due to a duplicate email.
func IsEmailAlreadyExists(err error) bool {
return internal.HasErrorCode(err, emailAlredyExists)
}

// IsIDTokenRevoked checks if the given error was due to a revoked ID token.
func IsIDTokenRevoked(err error) bool {
return internal.HasErrorCode(err, idTokenRevoked)
}

// IsInsufficientPermission checks if the given error was due to insufficient permissions.
func IsInsufficientPermission(err error) bool {
return internal.HasErrorCode(err, insufficientPermission)
}

// IsPhoneNumberAlreadyExists checks if the given error was due to a duplicate phone number.
func IsPhoneNumberAlreadyExists(err error) bool {
return internal.HasErrorCode(err, phoneNumberAlreadyExists)
}

// IsProjectNotFound checks if the given error was due to a non-existing project.
func IsProjectNotFound(err error) bool {
return internal.HasErrorCode(err, projectNotFound)
}

// IsUIDAlreadyExists checks if the given error was due to a duplicate uid.
func IsUIDAlreadyExists(err error) bool {
return internal.HasErrorCode(err, uidAlreadyExists)
}

// IsUnknown checks if the given error was due to a unknown server error.
func IsUnknown(err error) bool {
return internal.HasErrorCode(err, unknown)
}

// IsUserNotFound checks if the given error was due to non-existing user.
func IsUserNotFound(err error) bool {
return internal.HasErrorCode(err, userNotFound)
}

var serverError = map[string]string{
"CONFIGURATION_NOT_FOUND": projectNotFound,
"DUPLICATE_EMAIL": emailAlredyExists,
"DUPLICATE_LOCAL_ID": uidAlreadyExists,
"EMAIL_EXISTS": emailAlredyExists,
"INSUFFICIENT_PERMISSION": insufficientPermission,
"PHONE_NUMBER_EXISTS": phoneNumberAlreadyExists,
"PROJECT_NOT_FOUND": projectNotFound,
}

func handleServerError(err error) error {
gerr, ok := err.(*googleapi.Error)
if !ok {
// Not a back-end error
return err
}
serverCode := gerr.Message
clientCode, ok := serverError[serverCode]
if !ok {
clientCode = unknown
}
return internal.Error(clientCode, err.Error())
}

// Validators.

func validateDisplayName(val interface{}) error {
Expand Down Expand Up @@ -532,7 +610,7 @@ func (c *Client) createUser(ctx context.Context, user *UserToCreate) (string, er
c.setHeader(call)
resp, err := call.Context(ctx).Do()
if err != nil {
return "", err
return "", handleServerError(err)
}

return resp.LocalId, nil
Expand All @@ -555,20 +633,29 @@ func (c *Client) updateUser(ctx context.Context, uid string, user *UserToUpdate)

call := c.is.Relyingparty.SetAccountInfo(request)
c.setHeader(call)
_, err := call.Context(ctx).Do()

return err
if _, err := call.Context(ctx).Do(); err != nil {
return handleServerError(err)
}
return nil
}

func (c *Client) getUser(ctx context.Context, request *identitytoolkit.IdentitytoolkitRelyingpartyGetAccountInfoRequest) (*UserRecord, error) {
call := c.is.Relyingparty.GetAccountInfo(request)
c.setHeader(call)
resp, err := call.Context(ctx).Do()
if err != nil {
return nil, err
return nil, handleServerError(err)
}
if len(resp.Users) == 0 {
return nil, fmt.Errorf("cannot find user given params: id:%v, phone:%v, email: %v", request.LocalId, request.PhoneNumber, request.Email)
var msg string
if len(request.LocalId) == 1 {
msg = fmt.Sprintf("cannot find user from uid: %q", request.LocalId[0])
} else if len(request.Email) == 1 {
msg = fmt.Sprintf("cannot find user from email: %q", request.Email[0])
} else {
msg = fmt.Sprintf("cannot find user from phone number: %q", request.PhoneNumber[0])
}
return nil, internal.Error(userNotFound, msg)
}

eu, err := makeExportedUser(resp.Users[0])
Expand All @@ -581,8 +668,7 @@ func (c *Client) getUser(ctx context.Context, request *identitytoolkit.Identityt
func makeExportedUser(r *identitytoolkit.UserInfo) (*ExportedUserRecord, error) {
var cc map[string]interface{}
if r.CustomAttributes != "" {
err := json.Unmarshal([]byte(r.CustomAttributes), &cc)
if err != nil {
if err := json.Unmarshal([]byte(r.CustomAttributes), &cc); err != nil {
return nil, err
}
if len(cc) == 0 {
Expand Down
45 changes: 35 additions & 10 deletions auth/user_mgt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,21 @@ func TestGetNonExistingUser(t *testing.T) {
s := echoServer([]byte(resp), t)
defer s.Close()

want := "cannot find user given params: id:[%s], phone:[%s], email: [%s]"

we := fmt.Sprintf(want, "id-nonexisting", "", "")
we := `cannot find user from uid: "id-nonexisting"`
user, err := s.Client.GetUser(context.Background(), "id-nonexisting")
if user != nil || err == nil || err.Error() != we {
if user != nil || err == nil || err.Error() != we || !IsUserNotFound(err) {
t.Errorf("GetUser(non-existing) = (%v, %q); want = (nil, %q)", user, err, we)
}

we = fmt.Sprintf(want, "", "", "[email protected]")
we = `cannot find user from email: "[email protected]"`
user, err = s.Client.GetUserByEmail(context.Background(), "[email protected]")
if user != nil || err == nil || err.Error() != we {
if user != nil || err == nil || err.Error() != we || !IsUserNotFound(err) {
t.Errorf("GetUserByEmail(non-existing) = (%v, %q); want = (nil, %q)", user, err, we)
}

we = fmt.Sprintf(want, "", "+12345678901", "")
we = `cannot find user from phone number: "+12345678901"`
user, err = s.Client.GetUserByPhoneNumber(context.Background(), "+12345678901")
if user != nil || err == nil || err.Error() != we {
if user != nil || err == nil || err.Error() != we || !IsUserNotFound(err) {
t.Errorf("GetUserPhoneNumber(non-existing) = (%v, %q); want = (nil, %q)", user, err, we)
}
}
Expand Down Expand Up @@ -642,7 +640,6 @@ func TestInvalidDeleteUser(t *testing.T) {
}

func TestMakeExportedUser(t *testing.T) {

rur := &identitytoolkit.UserInfo{
LocalId: "testuser",
Email: "[email protected]",
Expand Down Expand Up @@ -704,11 +701,39 @@ func TestHTTPError(t *testing.T) {
}

want := `googleapi: got HTTP response code 500 with body: {"error":"test"}`
if err.Error() != want {
if err.Error() != want || !IsUnknown(err) {
t.Errorf("GetUser() = %v; want = %q", err, want)
}
}

func TestHTTPErrorWithCode(t *testing.T) {
errorCodes := map[string]func(error) bool{
"CONFIGURATION_NOT_FOUND": IsProjectNotFound,
"DUPLICATE_EMAIL": IsEmailAlreadyExists,
"DUPLICATE_LOCAL_ID": IsUIDAlreadyExists,
"EMAIL_EXISTS": IsEmailAlreadyExists,
"INSUFFICIENT_PERMISSION": IsInsufficientPermission,
"PHONE_NUMBER_EXISTS": IsPhoneNumberAlreadyExists,
"PROJECT_NOT_FOUND": IsProjectNotFound,
}
s := echoServer(nil, t)
defer s.Close()
s.Status = http.StatusInternalServerError

for code, check := range errorCodes {
s.Resp = []byte(fmt.Sprintf(`{"error":{"message":"%s"}}`, code))
u, err := s.Client.GetUser(context.Background(), "some uid")
if u != nil || err == nil {
t.Fatalf("GetUser() = (%v, %v); want = (nil, error)", u, err)
}

want := fmt.Sprintf("googleapi: Error 500: %s", code)
if err.Error() != want || !check(err) {
t.Errorf("GetUser() = %v; want = %q", err, want)
}
}
}

type mockAuthServer struct {
Resp []byte
Header map[string]string
Expand Down
2 changes: 1 addition & 1 deletion db/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package db
package db // import "firebase.google.com/go/db"

import (
"encoding/json"
Expand Down
4 changes: 2 additions & 2 deletions firebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// Package firebase is the entry point to the Firebase Admin SDK. It provides functionality for initializing App
// instances, which serve as the central entities that provide access to various other Firebase services exposed
// from the SDK.
package firebase
package firebase // import "firebase.google.com/go"

import (
"encoding/json"
Expand All @@ -42,7 +42,7 @@ import (
var defaultAuthOverrides = make(map[string]interface{})

// Version of the Firebase Go Admin SDK.
const Version = "2.6.1"
const Version = "2.7.0"

// firebaseEnvName is the name of the environment variable with the Config.
const firebaseEnvName = "FIREBASE_CONFIG"
Expand Down
2 changes: 1 addition & 1 deletion iid/iid.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

// Package iid contains functions for deleting instance IDs from Firebase projects.
package iid
package iid // import "firebase.google.com/go/iid"

import (
"errors"
Expand Down
Loading