From e96732cf5d09ef286a94b2e1354767cf90f6102b Mon Sep 17 00:00:00 2001
From: Cornel Rautenbach <cornel.rautenbach@gmail.com>
Date: Mon, 6 Jan 2025 21:53:24 +0200
Subject: [PATCH] Validate Apple auth

---
 auth/social_login.go          | 52 +++++++++++++++++++++++++++++++++++
 encryption/encryption_keys.go |  6 ++++
 go.mod                        |  2 ++
 go.sum                        |  4 +++
 string_utils/string_utils.go  |  8 ++++++
 5 files changed, 72 insertions(+)

diff --git a/auth/social_login.go b/auth/social_login.go
index 6d3c911..6ef1c27 100644
--- a/auth/social_login.go
+++ b/auth/social_login.go
@@ -2,7 +2,10 @@ package auth
 
 import (
 	"context"
+	"github.com/Timothylock/go-signin-with-apple/apple"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/encryption"
 	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/errors"
+	"gitlab.bob.co.za/bob-public-utils/bobgroup-go-utils/string_utils"
 	"google.golang.org/api/idtoken"
 )
 
@@ -19,3 +22,52 @@ func ValidateGoogleIDToken(tokenString, clientID string) (string, error) {
 
 	return email, nil
 }
+
+func ValidateAppleCode(code, redirectURI, encryptionKeySecret string, isDebug bool) (string, error) {
+	teamID := "7978M5K9YV"
+	clientID := "za.co.bob.auth.client"
+	keyID := "6X88ZTK5S4"
+
+	signingKey, err := encryption.GetAppleSigningKey(encryptionKeySecret, isDebug)
+	if err != nil {
+		return "", errors.Error("apple signing key not set up")
+	}
+
+	clientSecret, err := apple.GenerateClientSecret(signingKey, teamID, clientID, keyID)
+	if err != nil {
+		return "", err
+	}
+
+	client := apple.New()
+
+	var validationResponse apple.ValidationResponse
+
+	err = client.VerifyWebToken(context.Background(), apple.WebValidationTokenRequest{
+		ClientID:     clientID,
+		ClientSecret: clientSecret,
+		RedirectURI:  redirectURI,
+		Code:         code,
+	}, &validationResponse)
+
+	if err != nil {
+		return "", err
+	}
+
+	if validationResponse.ErrorDescription != "" {
+		panic(validationResponse.ErrorDescription)
+	}
+
+	claim, _ := apple.GetClaims(validationResponse.IDToken)
+	if claim == nil {
+		return "", errors.Error("invalid apple token")
+	}
+
+	email := (*claim)["email"]
+	emailVerified := (*claim)["email_verified"]
+
+	if emailVerified != "true" {
+		return "", errors.Error("email not verified")
+	}
+
+	return string_utils.InterfaceToString(email)
+}
diff --git a/encryption/encryption_keys.go b/encryption/encryption_keys.go
index 792d0e9..6b0f9ec 100644
--- a/encryption/encryption_keys.go
+++ b/encryption/encryption_keys.go
@@ -18,6 +18,7 @@ type EncryptionKeys struct {
 	GenericEncryptionKey      string `json:"generic_encryption_key"`
 	BobGoEncryptionKey        string `json:"bobgo_encryption_key"`
 	ShipLogicPINEncryptionKey string `json:"ship_logic_pin_encryption_key"`
+	AppleSigningKey           string `json:"apple_signing_key"`
 }
 
 func GetEncryptionKeys(secretID string, isDebug bool) (EncryptionKeys, error) {
@@ -66,3 +67,8 @@ func GetShipLogicPINEncryptionKey(secretID string, isDebug bool) (string, error)
 	encryptionKeys, err := GetEncryptionKeys(secretID, isDebug)
 	return encryptionKeys.ShipLogicPINEncryptionKey, err
 }
+
+func GetAppleSigningKey(secretID string, isDebug bool) (string, error) {
+	encryptionKeys, err := GetEncryptionKeys(secretID, isDebug)
+	return encryptionKeys.AppleSigningKey, err
+}
diff --git a/go.mod b/go.mod
index 7f1ab05..e48ccbb 100644
--- a/go.mod
+++ b/go.mod
@@ -47,6 +47,7 @@ require (
 	cloud.google.com/go/auth v0.13.0 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect
 	cloud.google.com/go/compute/metadata v0.6.0 // indirect
+	github.com/Timothylock/go-signin-with-apple v0.2.4 // indirect
 	github.com/aws/aws-sdk-go v1.44.180 // indirect
 	github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.2 // indirect
 	github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect
@@ -70,6 +71,7 @@ require (
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-pg/zerochecker v0.2.0 // indirect
 	github.com/go-stack/stack v1.8.1 // indirect
+	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/google/s2a-go v0.1.8 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
diff --git a/go.sum b/go.sum
index 9b64ad7..014f865 100644
--- a/go.sum
+++ b/go.sum
@@ -11,6 +11,8 @@ github.com/AfterShip/email-verifier v1.4.0/go.mod h1:JNPV1KZpTq4TArmss1NAOJsTD8J
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/MindscapeHQ/raygun4go v1.1.1 h1:fk3Uknv9kQxUIwL3mywwHQRyfq3PaR9lE/e40K+OcY0=
 github.com/MindscapeHQ/raygun4go v1.1.1/go.mod h1:NW0eWi2Qs00ZcctO6owrVMY+h2HxzJVgQGDrTj2ysw4=
+github.com/Timothylock/go-signin-with-apple v0.2.4 h1:cOL5suxOU86bZ6oNpZFFHT0WL8EdABqm8dm04wVN+jw=
+github.com/Timothylock/go-signin-with-apple v0.2.4/go.mod h1:uWYGAdyZQ+E2LMWRVI+prmYXApGJ+UaNVlwMwfT12S4=
 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
 github.com/aws/aws-lambda-go v1.26.0 h1:6ujqBpYF7tdZcBvPIccs98SpeGfrt/UOVEiexfNIdHA=
@@ -126,6 +128,8 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
 github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
 github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
+github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
diff --git a/string_utils/string_utils.go b/string_utils/string_utils.go
index d00df87..51ff859 100644
--- a/string_utils/string_utils.go
+++ b/string_utils/string_utils.go
@@ -211,6 +211,14 @@ func ToJSONString(object interface{}) (string, error) {
 	return string(jsonBytes), nil
 }
 
+func InterfaceToString(value interface{}) (string, error) {
+	str, ok := value.(string)
+	if !ok {
+		return "", fmt.Errorf("value is not a string")
+	}
+	return str, nil
+}
+
 func Int64ToString(number int64) string {
 	return strconv.FormatInt(number, 10)
 }
-- 
GitLab