├── .dockerignore ├── .gitignore ├── Dockerfile ├── README.md ├── _resources ├── images │ ├── req_a_request.jpg │ ├── req_a_response.jpg │ ├── req_b_request.jpg │ ├── req_b_response.jpg │ └── requests_list.jpg ├── samples │ ├── checkin_request_body.bin │ ├── checkin_response_body.bin │ └── item.bin └── scripts │ └── generate.bat ├── api ├── api_in.go ├── api_out.go ├── checkin.pb.go ├── checkin.proto ├── checkin_utils.go ├── checkin_vtproto.pb.go ├── gaf.pb.go ├── gaf.proto ├── gaf_vtproto.pb.go ├── mcs.pb.go ├── mcs.proto ├── mcs_vtproto.pb.go ├── structs.go └── utils.go ├── client ├── client.go └── mtalk.go ├── constants └── constants.go ├── example.env ├── go.mod ├── lib.go └── lib_test.go /.dockerignore: -------------------------------------------------------------------------------- 1 | *.md 2 | *.go 3 | **/*.go 4 | _resources 5 | _examples 6 | go.* 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/bunnymediaserver/proto-builder:v0.0.1 AS builder 2 | WORKDIR /proto 3 | 4 | # Copy our repo 5 | COPY . ./ 6 | 7 | # Lib dependencies 8 | ENV GAU_VERSION "v0.0.26" 9 | RUN go get github.com/BRUHItsABunny/go-android-utils@$GAU_VERSION 10 | 11 | # Setup general includes 12 | ENV PROTO_INC "-I ./ \ 13 | -I ../ \ 14 | -I ../../ \ 15 | -I $GOPATH/src \ 16 | -I $GOPATH/pkg/mod \ 17 | -I $GOPATH/pkg/mod/github.com/!b!r!u!h!its!a!bunny/go-android-utils@$GAU_VERSION" 18 | 19 | ENV TARGETS "api" 20 | ENV PROTOC_VT_DRPC "protoc ${PROTO_INC} --go_out=. --plugin protoc-gen-go=${GOPATH}/bin/protoc-gen-go --go-grpc_out=. --plugin protoc-gen-go-grpc=${GOPATH}/bin/protoc-gen-go-grpc --go-vtproto_out=. --plugin protoc-gen-go-vtproto=${GOPATH}/bin/protoc-gen-go-vtproto --go-vtproto_opt=features=marshal+unmarshal+size ./*.proto" 21 | 22 | RUN for target in ${TARGETS}; do cd /proto/$target && ${PROTOC_VT_DRPC} && find . -name "*.go" -type f -exec cp {} /proto/$target \; && rm -r /proto/$target/github.com; done 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # proto-builder 2 | This image we use to build our Protobuf code from IDL, this is containerized to prevent cross platform issues. 3 | 4 | ### Setup guide 5 | In order to use this perfectly you will need to build the image under a specific name 6 | 7 | I suggest: 8 | ``docker build -t bms-proto-builder .`` 9 | -------------------------------------------------------------------------------- /_resources/images/req_a_request.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/images/req_a_request.jpg -------------------------------------------------------------------------------- /_resources/images/req_a_response.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/images/req_a_response.jpg -------------------------------------------------------------------------------- /_resources/images/req_b_request.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/images/req_b_request.jpg -------------------------------------------------------------------------------- /_resources/images/req_b_response.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/images/req_b_response.jpg -------------------------------------------------------------------------------- /_resources/images/requests_list.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/images/requests_list.jpg -------------------------------------------------------------------------------- /_resources/samples/checkin_request_body.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/samples/checkin_request_body.bin -------------------------------------------------------------------------------- /_resources/samples/checkin_response_body.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/samples/checkin_response_body.bin -------------------------------------------------------------------------------- /_resources/samples/item.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUHItsABunny/go-android-firebase/86fe5d75b58533cc9970b3368b6ada36690b559b/_resources/samples/item.bin -------------------------------------------------------------------------------- /_resources/scripts/generate.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | docker build -t gaf_protos . 3 | docker run --name="gaf_protos_run" gaf_protos 4 | docker cp gaf_protos_run:proto/. . 5 | docker rm gaf_protos_run 6 | docker rmi gaf_protos 7 | echo "BAT done" -------------------------------------------------------------------------------- /api/api_in.go: -------------------------------------------------------------------------------- 1 | package firebase_api 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | gokhttp_responses "github.com/BRUHItsABunny/gOkHttp/responses" 7 | "net/http" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func NotifyInstallationResult(resp *http.Response) (*FireBaseInstallationResponse, error) { 14 | result := new(FireBaseInstallationResponse) 15 | err := gokhttp_responses.CheckHTTPCode(resp, http.StatusOK) 16 | if err != nil { 17 | err = fmt.Errorf("gokhttp_responses.CheckHTTPCode: %w", err) 18 | return nil, err 19 | } 20 | err = gokhttp_responses.ResponseJSON(resp, result) 21 | if err != nil { 22 | return nil, fmt.Errorf("gokhttp_responses.ResponseJSON: %w", err) 23 | } 24 | return result, nil 25 | } 26 | 27 | func VerifyPasswordResult(resp *http.Response) (*GoogleVerifyPasswordResponse, error) { 28 | result := new(GoogleVerifyPasswordResponse) 29 | err := gokhttp_responses.ResponseJSON(resp, result) 30 | if err != nil { 31 | return nil, fmt.Errorf("gokhttp_responses.ResponseJSON: %w", err) 32 | } 33 | return result, nil 34 | } 35 | 36 | func SignUpNewUserResult(resp *http.Response) (*GoogleSignUpNewUserResponse, error) { 37 | result := new(GoogleSignUpNewUserResponse) 38 | err := gokhttp_responses.ResponseJSON(resp, result) 39 | if err != nil { 40 | return nil, fmt.Errorf("gokhttp_responses.ResponseJSON: %w", err) 41 | } 42 | return result, nil 43 | } 44 | 45 | func SetAccountInfoResult(resp *http.Response) (*GoogleSetAccountInfoResponse, error) { 46 | result := new(GoogleSetAccountInfoResponse) 47 | err := gokhttp_responses.ResponseJSON(resp, result) 48 | if err != nil { 49 | return nil, fmt.Errorf("gokhttp_responses.ResponseJSON: %w", err) 50 | } 51 | return result, nil 52 | } 53 | 54 | func RefreshSecureTokenResult(resp *http.Response) (*SecureTokenRefreshResponse, error) { 55 | result := new(SecureTokenRefreshResponse) 56 | err := gokhttp_responses.ResponseJSON(resp, result) 57 | if err != nil { 58 | return nil, fmt.Errorf("gokhttp_responses.ResponseJSON: %w", err) 59 | } 60 | return result, nil 61 | } 62 | 63 | func AuthResult(resp *http.Response) (*AuthResponse, error) { 64 | result := new(AuthResponse) 65 | responseBody, err := gokhttp_responses.ResponseBytes(resp) 66 | if err != nil { 67 | return nil, fmt.Errorf("gokhttp_responses.ResponseBytes: %w", err) 68 | } 69 | var timeStamp int64 70 | for _, entryBytes := range bytes.Split(responseBody, []byte("\n")) { 71 | entryParts := bytes.Split(entryBytes, []byte("=")) 72 | switch string(entryParts[0]) { 73 | case "Expiry": 74 | timeStamp, err = strconv.ParseInt(string(entryParts[1]), 10, 64) 75 | result.Expires = time.Unix(timeStamp, 0) 76 | break 77 | case "grantedScopes": 78 | result.Scopes = strings.Split(string(entryParts[1]), " ") 79 | break 80 | case "itMetadata": 81 | result.Metadata = string(entryParts[1]) 82 | break 83 | case "it": 84 | result.Token = string(entryParts[1]) 85 | break 86 | case "Auth": 87 | result.Token = string(entryParts[1]) 88 | break 89 | default: 90 | continue 91 | } 92 | if err != nil { 93 | break 94 | } 95 | } 96 | return result, err 97 | } 98 | 99 | func CheckinResult(resp *http.Response) (*CheckinResponse, error) { 100 | result := new(CheckinResponse) 101 | responseBody, err := gokhttp_responses.ResponseBytes(resp) 102 | if err != nil { 103 | return nil, fmt.Errorf("gokhttp_responses.ResponseBytes: %w", err) 104 | } 105 | err = result.UnmarshalVT(responseBody) 106 | if err != nil { 107 | return nil, fmt.Errorf("result.UnmarshalVT: %w", err) 108 | } 109 | return result, nil 110 | } 111 | 112 | func AndroidRegisterResult(resp *http.Response) (string, error) { 113 | responseBody, err := gokhttp_responses.ResponseBytes(resp) 114 | if err != nil { 115 | return "", fmt.Errorf("gokhttp_responses.ResponseBytes: %w", err) 116 | } 117 | return string(responseBody[6:]), nil 118 | } 119 | -------------------------------------------------------------------------------- /api/api_out.go: -------------------------------------------------------------------------------- 1 | package firebase_api 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "fmt" 9 | "github.com/BRUHItsABunny/gOkHttp/requests" 10 | . "github.com/BRUHItsABunny/go-android-firebase/constants" 11 | andutils "github.com/BRUHItsABunny/go-android-utils" 12 | "net/http" 13 | "net/url" 14 | "strconv" 15 | "strings" 16 | ) 17 | 18 | func NotifyInstallationRequest(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData) (*http.Request, error) { 19 | fid, _ := RandomAppFID() 20 | gmpAppID := appData.GMPAppID 21 | authVersion := appData.AuthVersion 22 | sdkVersion := appData.SdkVersion 23 | 24 | installationData, ok := device.FirebaseInstallations[appData.PackageID] 25 | if ok { 26 | fid = installationData.FirebaseInstallationID 27 | } 28 | 29 | data := NotifyInstallationRequestBody{ 30 | FID: fid, 31 | AppID: gmpAppID, 32 | AuthVersion: authVersion, 33 | SDKVersion: sdkVersion, 34 | } 35 | 36 | body, err := json.Marshal(data) 37 | if err != nil { 38 | return nil, fmt.Errorf("json.Marshal: %w", err) 39 | } 40 | 41 | req, err := gokhttp_requests.MakePOSTRequest(ctx, fmt.Sprintf(EndpointInstallations, appData.FirebaseProjectID), 42 | gokhttp_requests.NewPOSTRawOption(bytes.NewBuffer(body), HeaderValueMIMEJSON, int64(len(body))), 43 | gokhttp_requests.NewHeaderOption(DefaultHeadersFirebase(device, appData, true, true, false)), 44 | ) 45 | if err != nil { 46 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 47 | } 48 | return req, err 49 | } 50 | 51 | func VerifyPasswordRequest(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData, data *VerifyPasswordRequestBody) (*http.Request, error) { 52 | body, err := json.Marshal(data) 53 | if err != nil { 54 | return nil, fmt.Errorf("json.Marshal: %w", err) 55 | } 56 | 57 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointVerifyPassword, 58 | gokhttp_requests.NewURLParamOption(url.Values{"key": {appData.GoogleAPIKey}}), 59 | gokhttp_requests.NewPOSTRawOption(bytes.NewBuffer(body), HeaderValueMIMEJSON, int64(len(body))), 60 | gokhttp_requests.NewHeaderOption(DefaultHeadersFirebase(device, appData, false, false, true)), 61 | ) 62 | if err != nil { 63 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 64 | } 65 | return req, err 66 | } 67 | 68 | func SignUpNewUser(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData, data *SignUpNewUserRequestBody) (*http.Request, error) { 69 | body, err := json.Marshal(data) 70 | if err != nil { 71 | return nil, fmt.Errorf("json.Marshal: %w", err) 72 | } 73 | 74 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointSignUpNewUser, 75 | gokhttp_requests.NewURLParamOption(url.Values{"key": {appData.GoogleAPIKey}}), 76 | gokhttp_requests.NewPOSTRawOption(bytes.NewBuffer(body), HeaderValueMIMEJSON, int64(len(body))), 77 | gokhttp_requests.NewHeaderOption(DefaultHeadersFirebase(device, appData, false, false, true)), 78 | ) 79 | if err != nil { 80 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 81 | } 82 | return req, err 83 | } 84 | 85 | func SetAccountInfoRequest(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData, data *SetAccountInfoRequestBody) (*http.Request, error) { 86 | body, err := json.Marshal(data) 87 | if err != nil { 88 | return nil, fmt.Errorf("json.Marshal: %w", err) 89 | } 90 | 91 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointSetAccountInto, 92 | gokhttp_requests.NewURLParamOption(url.Values{"key": {appData.GoogleAPIKey}}), 93 | gokhttp_requests.NewPOSTRawOption(bytes.NewBuffer(body), HeaderValueMIMEJSON, int64(len(body))), 94 | gokhttp_requests.NewHeaderOption(DefaultHeadersFirebase(device, appData, false, false, true)), 95 | ) 96 | if err != nil { 97 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 98 | } 99 | return req, err 100 | } 101 | 102 | func RefreshSecureTokenRequest(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData, data *RefreshSecureTokenRequestBody) (*http.Request, error) { 103 | body, err := json.Marshal(data) 104 | if err != nil { 105 | return nil, fmt.Errorf("json.Marshal: %w", err) 106 | } 107 | 108 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointRefreshSecureToken, 109 | gokhttp_requests.NewURLParamOption(url.Values{"key": {appData.GoogleAPIKey}}), 110 | gokhttp_requests.NewPOSTRawOption(bytes.NewBuffer(body), HeaderValueMIMEJSON, int64(len(body))), 111 | gokhttp_requests.NewHeaderOption(DefaultHeadersFirebase(device, appData, false, false, true)), 112 | ) 113 | if err != nil { 114 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 115 | } 116 | return req, err 117 | } 118 | 119 | func AuthRequest(ctx context.Context, device *andutils.Device, appData *FirebaseAppData, data url.Values) (*http.Request, error) { 120 | data["androidId"] = []string{device.Id.ToHexString()} 121 | data["lang"] = []string{device.Locale.ToLocale("-", true)} 122 | data["device_country"] = []string{device.Locale.GetCountry(false)} 123 | data["sdk_version"] = []string{device.Version.ToAndroidSDK()} 124 | 125 | if appData != nil { 126 | if appData.PackageID != "" { 127 | data["callerPkg"] = []string{appData.PackageID} 128 | data["app"] = []string{appData.PackageID} 129 | } 130 | if appData.PackageCertificate != "" { 131 | data["callerSig"] = []string{strings.ToLower(appData.PackageCertificate)} 132 | data["client_sig"] = []string{strings.ToLower(appData.PackageCertificate)} 133 | } 134 | } 135 | 136 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointRefreshSecureToken, 137 | gokhttp_requests.NewPOSTFormOption(data), 138 | gokhttp_requests.NewHeaderOption(DefaultHeadersAuth(device)), 139 | ) 140 | if err != nil { 141 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 142 | } 143 | return req, err 144 | } 145 | 146 | func CheckinAndroidRequest(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData, digest, otaCert string, accountCookies ...string) (*http.Request, error) { 147 | reqObj := NewCheckinRequest(device.Device) 148 | if len(digest) > 0 { 149 | reqObj.Digest = &digest 150 | } 151 | if len(otaCert) > 0 { 152 | reqObj.OtaCert = []string{otaCert} 153 | } 154 | if len(accountCookies) > 0 { 155 | reqObj.AccountCookie = accountCookies 156 | } 157 | if device.CheckinAndroidID > 0 { 158 | reqObj.AndroidId = &device.CheckinAndroidID 159 | } 160 | if device.CheckinSecurityToken != 0 { 161 | reqObj.SecurityToken = &device.CheckinSecurityToken 162 | } 163 | reqBytes, err := reqObj.MarshalVT() 164 | if err != nil { 165 | return nil, fmt.Errorf("reqObj.MarshalVT: %w", err) 166 | } 167 | 168 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointAndroidCheckin, 169 | gokhttp_requests.NewPOSTRawOption(bytes.NewBuffer(reqBytes), "application/x-protobuffer", int64(len(reqBytes))), 170 | gokhttp_requests.NewHeaderOption(DefaultHeadersCheckin(device.Device)), 171 | ) 172 | if err != nil { 173 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 174 | } 175 | return req, err 176 | } 177 | 178 | func C2DMAndroidRegisterRequest(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData) (*http.Request, error) { 179 | installationData, ok := device.FirebaseInstallations[appData.PackageID] 180 | if !ok { 181 | return nil, errors.New("no installation available") 182 | } 183 | 184 | reqBody := url.Values{ 185 | "sender": {appData.NotificationSenderID}, 186 | "X-subtype": {appData.NotificationSenderID}, 187 | "X-app_ver": {appData.AppVersionWithBuild}, 188 | "X-osv": {device.Device.Version.ToAndroidSDK()}, 189 | "X-cliv": {device.FirebaseClientVersion}, // {"fcm-22.0.0"}, 190 | "X-gmsv": {device.GmsVersion}, // {"214815028"}, 191 | "X-appid": {installationData.FirebaseInstallationID}, 192 | "X-scope": {"*"}, 193 | "X-Goog-Firebase-Installations-Auth": {installationData.InstallationAuthentication.AccessToken}, 194 | "X-gmp_app_id": {appData.GMPAppID}, 195 | "X-Firebase-Client": {device.Device.FormatUserAgent(HeaderValueFireBaseClient)}, 196 | "X-firebase-app-name-hash": {appData.AppNameHash}, 197 | "X-Firebase-Client-Log-Type": {"1"}, 198 | "X-app_ver_name": {appData.AppVersion}, 199 | "app": {appData.PackageID}, 200 | "device": {strconv.FormatInt(device.CheckinAndroidID, 10)}, 201 | "app_ver": {appData.AppVersionWithBuild}, 202 | "gcm_ver": {device.GmsVersion}, //{"214815028"}, 203 | "plat": {"0"}, 204 | "cert": {strings.ToLower(appData.PackageCertificate)}, 205 | "target_ver": {device.Device.Version.ToAndroidSDK()}, // {"30"} 206 | } 207 | 208 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointAndroidRegister, 209 | gokhttp_requests.NewPOSTFormOption(reqBody), 210 | gokhttp_requests.NewHeaderOption(DefaultHeadersAndroidRegister(device)), 211 | ) 212 | if err != nil { 213 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 214 | } 215 | return req, err 216 | } 217 | 218 | func C2DMWebRegisterRequest(ctx context.Context, device *FirebaseDevice, appData *FirebaseAppData, sender, subType, appId string) (*http.Request, error) { 219 | reqBody := url.Values{ 220 | "sender": {sender}, 221 | "X-subscription": {sender}, 222 | "X-X-subscription": {sender}, 223 | "X-subtype": {"wp:" + subType + "-V2"}, 224 | "X-X-subtype": {"wp:" + subType + "-V2"}, 225 | "X-app_ver": {appData.AppVersionWithBuild}, 226 | "X-osv": {device.Device.Version.ToAndroidSDK()}, 227 | "X-cliv": {"iid-12451000"}, 228 | "X-gmsv": {device.GmsVersion}, // {"250632029"}, 229 | "X-appid": {appId}, 230 | "X-scope": {"GCM"}, 231 | "X-app_ver_name": {appData.AppVersion}, 232 | "app": {appData.PackageID}, 233 | "device": {strconv.FormatInt(device.CheckinAndroidID, 10)}, 234 | "app_ver": {appData.AppVersionWithBuild}, 235 | "gcm_ver": {device.GmsVersion}, //{"214815028"}, 236 | "plat": {"0"}, 237 | "cert": {strings.ToLower(appData.PackageCertificate)}, 238 | "target_ver": {device.Device.Version.ToAndroidSDK()}, // {"30"} 239 | } 240 | 241 | req, err := gokhttp_requests.MakePOSTRequest(ctx, EndpointAndroidRegister, 242 | gokhttp_requests.NewPOSTFormOption(reqBody), 243 | gokhttp_requests.NewHeaderOption(DefaultHeadersAndroidRegister(device)), 244 | ) 245 | if err != nil { 246 | return nil, fmt.Errorf("requests.MakePOSTRequest: %w", err) 247 | } 248 | return req, err 249 | } 250 | -------------------------------------------------------------------------------- /api/checkin.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | option java_package = "org.microg.gms.checkin"; 3 | 4 | option java_outer_classname = "CheckinProto"; 5 | option go_package = "github.com/BRUHItsABunny/go-android-firebase/firebase_api"; 6 | 7 | // Sample data, if provided, is fished from a Nexus 7 (2013) / flo running Android 5.0 8 | message CheckinRequest { 9 | // unused 10 | optional string imei = 1; 11 | 12 | // Gservices["android_id"] or 0 on first-checkin 13 | optional int64 androidId = 2; 14 | 15 | // Gservices["digest"] or "" 16 | optional string digest = 3; 17 | 18 | required Checkin checkin = 4; 19 | message Checkin { 20 | // empty Build on pre-checkin 21 | required Build build = 1; 22 | message Build { 23 | // Build.FINGERPRINT 24 | // eg. google/razor/flo:5.0.1/LRX22C/1602158:user/release-keys 25 | optional string fingerprint = 1; 26 | 27 | // Build.HARDWARE 28 | // eg. flo 29 | optional string hardware = 2; 30 | 31 | // Build.BRAND 32 | // eg. google 33 | optional string brand = 3; 34 | 35 | // Build.getRadioVersion() 36 | optional string radio = 4; 37 | 38 | // Build.BOOTLOADER 39 | // eg. FLO-04.04 40 | optional string bootloader = 5; 41 | 42 | // GoogleSettingsContract.Partner["client_id"] 43 | // eg. android-google 44 | optional string clientId = 6; 45 | 46 | // Build.TIME / 1000L 47 | // eg. 1416533192 48 | optional int64 time = 7; 49 | 50 | // PackageInfo.versionCode 51 | // eg. 6188736 52 | optional int32 packageVersionCode = 8; 53 | 54 | // Build.DEVICE 55 | // eg. flo 56 | optional string device = 9; 57 | 58 | // Build.VERSION.SDK_INT 59 | // eg. 21 60 | optional int32 sdkVersion = 10; 61 | 62 | // Build.MODEL 63 | // eg. Nexus 7 64 | optional string model = 11; 65 | 66 | // Build.MANUFACTURER 67 | // eg. asus 68 | optional string manufacturer = 12; 69 | 70 | // Build.PRODUCT 71 | // eg. razor 72 | optional string product = 13; 73 | 74 | // fileExists("/system/recovery-from-boot.p") 75 | // eg. false 76 | optional bool otaInstalled = 14; 77 | } 78 | 79 | // last checkin ms or 0 if first checkin 80 | // eg. 0 81 | optional int64 lastCheckinMs = 2; 82 | 83 | // eg. ("event_log_start",~,1424612602652) on first checkin 84 | repeated Event event = 3; 85 | message Event { 86 | optional string tag = 1; 87 | optional string value = 2; 88 | optional int64 timeMs = 3; 89 | } 90 | 91 | // unknown, n/a on first checkin 92 | repeated Statistic stat = 4; 93 | message Statistic { 94 | required string tag = 1; 95 | optional int32 count = 2; 96 | optional float sum = 3; 97 | } 98 | 99 | // unused 100 | repeated string requestedGroup = 5; 101 | 102 | // TelephonyManager.getNetworkOperator != null|empty 103 | optional string cellOperator = 6; 104 | 105 | // TelephonyManager.getSimOperator != null|empty 106 | optional string simOperator = 7; 107 | 108 | // "WIFI::" | ("mobile" | "notmobile" | "unknown") + "-" + ("roaming" | "notroaming" | "unknown") 109 | optional string roaming = 8; 110 | 111 | // UserHandle.myUserId 112 | // eg. 0 113 | optional int32 userNumber = 9; 114 | } 115 | 116 | // unused 117 | optional string desiredBuild = 5; 118 | 119 | // Locale.toString 120 | optional string locale = 6; 121 | 122 | // GoogleSettingsContract.Partner["logging_id2"] (choosen randomly on first checkin) 123 | // eg. 12561488293572742346 124 | optional int64 loggingId = 7; 125 | 126 | // unused 127 | optional string marketCheckin = 8; 128 | 129 | // NetworkInfo.getExtraInfo, WifiInfo.getMacAddress (12 hex-digits) 130 | // eg. d850e6abcdef 131 | repeated string macAddress = 9; 132 | 133 | // TelephonyManager.getDeviceId (14 hex-digits), not set on tablets 134 | optional string meid = 10; 135 | 136 | // "[]" followed by "", empty string on first checkin 137 | repeated string accountCookie = 11; 138 | 139 | // TimeZone.getId 140 | // eg. GMT 141 | optional string timeZone = 12; 142 | 143 | // security token as given on first checkin, not set on first checkin 144 | optional fixed64 securityToken = 13; 145 | 146 | // use 3 147 | optional int32 version = 14; 148 | 149 | // SHA-1 of each in /system/etc/security/otacerts.zip or "--IOException--" or "--no-output--" 150 | // eg. dKXTm1QH9QShGQwBM/4rg6/lCNQ= 151 | repeated string otaCert = 15; 152 | 153 | // Build.SERIAL != "unknown" 154 | // eg. 07d90b18 155 | optional string serial = 16; 156 | 157 | // TelephonyManager.getDeviceId (8 hex-digits), not set on tablets 158 | optional string esn = 17; 159 | 160 | optional DeviceConfig deviceConfiguration = 18; 161 | message DeviceConfig { 162 | // ConfigurationInfo.reqTouchScreen 163 | // eg. 3 164 | optional int32 touchScreen = 1; 165 | 166 | // ConfigurationInfo.reqKeyboardType 167 | // eg. 1 168 | optional int32 keyboardType = 2; 169 | 170 | // ConfigurationInfo.reqNavigation 171 | // eg. 1 172 | optional int32 navigation = 3; 173 | // ConfigurationInfo.screenLayout 174 | // eg. 3 175 | optional int32 screenLayout = 4; 176 | 177 | // ConfigurationInfo.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD 178 | // eg. 0 179 | optional bool hasHardKeyboard = 5; 180 | 181 | // ConfigurationInfo.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV 182 | // eg. 0 183 | optional bool hasFiveWayNavigation = 6; 184 | 185 | // DisplayMetrics.densityDpi 186 | // eg. 320 187 | optional int32 densityDpi = 7; 188 | 189 | // ConfigurationInfo.reqGlEsVersion 190 | // eg. 196608 191 | optional int32 glEsVersion = 8; 192 | 193 | // PackageManager.getSystemSharedLibraryNames 194 | // eg. "android.test.runner", "com.android.future.usb.accessory", "com.android.location.provider", 195 | // "com.android.media.remotedisplay", "com.android.mediadrm.signer", "com.google.android.maps", 196 | // "com.google.android.media.effects", "com.google.widevine.software.drm", "javax.obex" 197 | repeated string sharedLibrary = 9; 198 | 199 | // PackageManager.getSystemAvailableFeatures 200 | // eg. android.hardware.[...] 201 | repeated string availableFeature = 10; 202 | 203 | // Build.CPU_ABI and Build.CPU_ABI2 != "unknown" 204 | // eg. "armeabi-v7a", "armeabi" 205 | repeated string nativePlatform = 11; 206 | 207 | // DisplayMetrics.widthPixels 208 | // eg. 1200 209 | optional int32 widthPixels = 12; 210 | 211 | // DisplayMetrics.heightPixels 212 | // eg. 1824 213 | optional int32 heightPixels = 13; 214 | 215 | // Context.getAssets.getLocales 216 | // eg. [...], "en-US", [...] 217 | repeated string locale = 14; 218 | 219 | // GLES10.glGetString(GLES10.GL_EXTENSIONS) 220 | // eg. "GL_AMD_compressed_ATC_texture", [...] 221 | repeated string glExtension = 15; 222 | 223 | // unused 224 | optional int32 deviceClass = 16; 225 | // unused 226 | optional int32 maxApkDownloadSizeMb = 17; 227 | } 228 | 229 | // "ethernet" or "wifi" 230 | repeated string macAddressType = 19; 231 | 232 | // unknown, use 0 on pre- and first-checkin, and 1 for later checkins 233 | // also present on pre-checkin 234 | required int32 fragment = 20; 235 | 236 | // unknown 237 | optional string userName = 21; 238 | 239 | // UserManager.getUserSerialNumber 240 | // eg. 0 241 | optional int32 userSerialNumber = 22; 242 | } 243 | 244 | message CheckinResponse { 245 | optional bool statsOk = 1; 246 | repeated Intent intent = 2; 247 | message Intent { 248 | optional string action = 1; 249 | optional string dataUri = 2; 250 | optional string mimeType = 3; 251 | optional string javaClass = 4; 252 | repeated Extra extra = 5; 253 | message Extra { 254 | optional string name = 6; 255 | optional string value = 7; 256 | } 257 | } 258 | optional int64 timeMs = 3; 259 | optional string digest = 4; 260 | repeated GservicesSetting setting = 5; 261 | message GservicesSetting { 262 | optional bytes name = 1; 263 | optional bytes value = 2; 264 | } 265 | optional bool marketOk = 6; 266 | optional fixed64 androidId = 7; 267 | optional fixed64 securityToken = 8; 268 | optional bool settingsDiff = 9; 269 | repeated string deleteSetting = 10; 270 | optional string versionInfo = 11; 271 | optional string deviceDataVersionInfo = 12; 272 | } -------------------------------------------------------------------------------- /api/checkin_utils.go: -------------------------------------------------------------------------------- 1 | package firebase_api 2 | 3 | import ( 4 | andutils "github.com/BRUHItsABunny/go-android-utils" 5 | "google.golang.org/protobuf/proto" 6 | "math/rand" 7 | "time" 8 | ) 9 | 10 | func NewCheckinRequest(device *andutils.Device) *CheckinRequest { 11 | currentTimeStamp := proto.Int64(time.Now().UnixMilli()) 12 | hni := "000000" 13 | if len(device.SimSlots) > 0 { 14 | hni = device.SimSlots[0].GetHNI() 15 | } 16 | result := &CheckinRequest{ 17 | AndroidId: proto.Int64(0), 18 | Digest: proto.String("1-929a0dca0eee55513280171a8585da7dcd3700f8"), // INITIAL_DIGEST src: https://github.com/microg/GmsCore/blob/4a5c98491bcfe4754b3efcfed20f3ada75a6ebec/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt 19 | Checkin: &CheckinRequest_Checkin{ 20 | Build: &CheckinRequest_Checkin_Build{ 21 | Fingerprint: proto.String(device.GetFingerprint()), 22 | Brand: proto.String(device.Manufacturer), 23 | Bootloader: proto.String(device.IncrementalVersion), // Technically inaccurate 24 | ClientId: proto.String("android-google"), 25 | Time: currentTimeStamp, 26 | Device: proto.String(device.Device), 27 | SdkVersion: proto.Int32(int32(device.Version)), 28 | Model: proto.String(device.Model), 29 | Manufacturer: proto.String(device.Manufacturer), 30 | Product: proto.String(device.Product), 31 | OtaInstalled: proto.Bool(false), 32 | }, 33 | LastCheckinMs: proto.Int64(0), 34 | Event: []*CheckinRequest_Checkin_Event{{ 35 | Tag: proto.String("event_log_start"), 36 | TimeMs: currentTimeStamp, 37 | }}, 38 | CellOperator: &hni, 39 | SimOperator: &hni, 40 | Roaming: proto.String("mobile-notroaming"), 41 | UserNumber: proto.Int32(0), 42 | }, 43 | Locale: proto.String(device.Locale.ToLocale("_", true)), 44 | LoggingId: proto.Int64(rand.Int63()), // Randomize? 45 | MacAddress: []string{device.MacAddress.Address}, 46 | Meid: proto.String(device.SimSlots[0].Imei.Imei), // TODO: use MEID instead 47 | AccountCookie: []string{""}, 48 | TimeZone: proto.String(device.Timezone.GetName()), 49 | Version: proto.Int32(3), 50 | OtaCert: []string{"--no-output--"}, // Randomize? 18 bytes base64 no padding or "--no-output--" 51 | DeviceConfiguration: &CheckinRequest_DeviceConfig{ 52 | TouchScreen: proto.Int32(3), 53 | KeyboardType: proto.Int32(1), 54 | Navigation: proto.Int32(1), 55 | ScreenLayout: proto.Int32(2), 56 | HasHardKeyboard: proto.Bool(false), 57 | HasFiveWayNavigation: proto.Bool(false), 58 | DensityDpi: proto.Int32(device.DPI), 59 | GlEsVersion: proto.Int32(196610), // Make configurable? 60 | NativePlatform: device.AbiList, 61 | WidthPixels: proto.Int32(device.ResolutionHorizontal), 62 | HeightPixels: proto.Int32(device.ResolutionVertical), 63 | Locale: nil, 64 | GlExtension: nil, 65 | SharedLibrary: nil, 66 | }, 67 | MacAddressType: []string{"wifi"}, 68 | Fragment: proto.Int32(0), 69 | } 70 | 71 | return result 72 | } 73 | -------------------------------------------------------------------------------- /api/gaf.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.27.1 4 | // protoc v3.19.4 5 | // source: gaf.proto 6 | 7 | package firebase_api 8 | 9 | import ( 10 | go_android_utils "github.com/BRUHItsABunny/go-android-utils" 11 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 12 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 13 | timestamppb "google.golang.org/protobuf/types/known/timestamppb" 14 | reflect "reflect" 15 | sync "sync" 16 | ) 17 | 18 | const ( 19 | // Verify that this generated code is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 21 | // Verify that runtime/protoimpl is sufficiently up-to-date. 22 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 23 | ) 24 | 25 | type FirebaseAuthentication struct { 26 | state protoimpl.MessageState 27 | sizeCache protoimpl.SizeCache 28 | unknownFields protoimpl.UnknownFields 29 | 30 | AccessToken string `protobuf:"bytes,1,opt,name=accessToken,proto3" json:"accessToken,omitempty"` 31 | Expires *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=expires,proto3" json:"expires,omitempty"` 32 | RefreshToken string `protobuf:"bytes,3,opt,name=refreshToken,proto3" json:"refreshToken,omitempty"` 33 | IdToken string `protobuf:"bytes,4,opt,name=idToken,proto3" json:"idToken,omitempty"` 34 | } 35 | 36 | func (x *FirebaseAuthentication) Reset() { 37 | *x = FirebaseAuthentication{} 38 | if protoimpl.UnsafeEnabled { 39 | mi := &file_gaf_proto_msgTypes[0] 40 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 41 | ms.StoreMessageInfo(mi) 42 | } 43 | } 44 | 45 | func (x *FirebaseAuthentication) String() string { 46 | return protoimpl.X.MessageStringOf(x) 47 | } 48 | 49 | func (*FirebaseAuthentication) ProtoMessage() {} 50 | 51 | func (x *FirebaseAuthentication) ProtoReflect() protoreflect.Message { 52 | mi := &file_gaf_proto_msgTypes[0] 53 | if protoimpl.UnsafeEnabled && x != nil { 54 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 55 | if ms.LoadMessageInfo() == nil { 56 | ms.StoreMessageInfo(mi) 57 | } 58 | return ms 59 | } 60 | return mi.MessageOf(x) 61 | } 62 | 63 | // Deprecated: Use FirebaseAuthentication.ProtoReflect.Descriptor instead. 64 | func (*FirebaseAuthentication) Descriptor() ([]byte, []int) { 65 | return file_gaf_proto_rawDescGZIP(), []int{0} 66 | } 67 | 68 | func (x *FirebaseAuthentication) GetAccessToken() string { 69 | if x != nil { 70 | return x.AccessToken 71 | } 72 | return "" 73 | } 74 | 75 | func (x *FirebaseAuthentication) GetExpires() *timestamppb.Timestamp { 76 | if x != nil { 77 | return x.Expires 78 | } 79 | return nil 80 | } 81 | 82 | func (x *FirebaseAuthentication) GetRefreshToken() string { 83 | if x != nil { 84 | return x.RefreshToken 85 | } 86 | return "" 87 | } 88 | 89 | func (x *FirebaseAuthentication) GetIdToken() string { 90 | if x != nil { 91 | return x.IdToken 92 | } 93 | return "" 94 | } 95 | 96 | type FirebaseNotificationData struct { 97 | state protoimpl.MessageState 98 | sizeCache protoimpl.SizeCache 99 | unknownFields protoimpl.UnknownFields 100 | 101 | NotificationToken string `protobuf:"bytes,1,opt,name=notificationToken,proto3" json:"notificationToken,omitempty"` 102 | // The fields below are needed for Chromium push notification, not for native Android apps (typically) 103 | PrivateKey []byte `protobuf:"bytes,2,opt,name=privateKey,proto3" json:"privateKey,omitempty"` 104 | PublicKey []byte `protobuf:"bytes,3,opt,name=publicKey,proto3" json:"publicKey,omitempty"` 105 | Secret []byte `protobuf:"bytes,4,opt,name=secret,proto3" json:"secret,omitempty"` 106 | } 107 | 108 | func (x *FirebaseNotificationData) Reset() { 109 | *x = FirebaseNotificationData{} 110 | if protoimpl.UnsafeEnabled { 111 | mi := &file_gaf_proto_msgTypes[1] 112 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 113 | ms.StoreMessageInfo(mi) 114 | } 115 | } 116 | 117 | func (x *FirebaseNotificationData) String() string { 118 | return protoimpl.X.MessageStringOf(x) 119 | } 120 | 121 | func (*FirebaseNotificationData) ProtoMessage() {} 122 | 123 | func (x *FirebaseNotificationData) ProtoReflect() protoreflect.Message { 124 | mi := &file_gaf_proto_msgTypes[1] 125 | if protoimpl.UnsafeEnabled && x != nil { 126 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 127 | if ms.LoadMessageInfo() == nil { 128 | ms.StoreMessageInfo(mi) 129 | } 130 | return ms 131 | } 132 | return mi.MessageOf(x) 133 | } 134 | 135 | // Deprecated: Use FirebaseNotificationData.ProtoReflect.Descriptor instead. 136 | func (*FirebaseNotificationData) Descriptor() ([]byte, []int) { 137 | return file_gaf_proto_rawDescGZIP(), []int{1} 138 | } 139 | 140 | func (x *FirebaseNotificationData) GetNotificationToken() string { 141 | if x != nil { 142 | return x.NotificationToken 143 | } 144 | return "" 145 | } 146 | 147 | func (x *FirebaseNotificationData) GetPrivateKey() []byte { 148 | if x != nil { 149 | return x.PrivateKey 150 | } 151 | return nil 152 | } 153 | 154 | func (x *FirebaseNotificationData) GetPublicKey() []byte { 155 | if x != nil { 156 | return x.PublicKey 157 | } 158 | return nil 159 | } 160 | 161 | func (x *FirebaseNotificationData) GetSecret() []byte { 162 | if x != nil { 163 | return x.Secret 164 | } 165 | return nil 166 | } 167 | 168 | type FirebaseInstallationData struct { 169 | state protoimpl.MessageState 170 | sizeCache protoimpl.SizeCache 171 | unknownFields protoimpl.UnknownFields 172 | 173 | FirebaseInstallationID string `protobuf:"bytes,1,opt,name=FirebaseInstallationID,proto3" json:"FirebaseInstallationID,omitempty"` 174 | NotificationData *FirebaseNotificationData `protobuf:"bytes,2,opt,name=notificationData,proto3" json:"notificationData,omitempty"` 175 | InstallationAuthentication *FirebaseAuthentication `protobuf:"bytes,3,opt,name=installationAuthentication,proto3" json:"installationAuthentication,omitempty"` // Upon NotifyInstall 176 | } 177 | 178 | func (x *FirebaseInstallationData) Reset() { 179 | *x = FirebaseInstallationData{} 180 | if protoimpl.UnsafeEnabled { 181 | mi := &file_gaf_proto_msgTypes[2] 182 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 183 | ms.StoreMessageInfo(mi) 184 | } 185 | } 186 | 187 | func (x *FirebaseInstallationData) String() string { 188 | return protoimpl.X.MessageStringOf(x) 189 | } 190 | 191 | func (*FirebaseInstallationData) ProtoMessage() {} 192 | 193 | func (x *FirebaseInstallationData) ProtoReflect() protoreflect.Message { 194 | mi := &file_gaf_proto_msgTypes[2] 195 | if protoimpl.UnsafeEnabled && x != nil { 196 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 197 | if ms.LoadMessageInfo() == nil { 198 | ms.StoreMessageInfo(mi) 199 | } 200 | return ms 201 | } 202 | return mi.MessageOf(x) 203 | } 204 | 205 | // Deprecated: Use FirebaseInstallationData.ProtoReflect.Descriptor instead. 206 | func (*FirebaseInstallationData) Descriptor() ([]byte, []int) { 207 | return file_gaf_proto_rawDescGZIP(), []int{2} 208 | } 209 | 210 | func (x *FirebaseInstallationData) GetFirebaseInstallationID() string { 211 | if x != nil { 212 | return x.FirebaseInstallationID 213 | } 214 | return "" 215 | } 216 | 217 | func (x *FirebaseInstallationData) GetNotificationData() *FirebaseNotificationData { 218 | if x != nil { 219 | return x.NotificationData 220 | } 221 | return nil 222 | } 223 | 224 | func (x *FirebaseInstallationData) GetInstallationAuthentication() *FirebaseAuthentication { 225 | if x != nil { 226 | return x.InstallationAuthentication 227 | } 228 | return nil 229 | } 230 | 231 | type FirebaseAppData struct { 232 | state protoimpl.MessageState 233 | sizeCache protoimpl.SizeCache 234 | unknownFields protoimpl.UnknownFields 235 | 236 | PackageID string `protobuf:"bytes,1,opt,name=packageID,proto3" json:"packageID,omitempty"` // com.app.my 237 | PackageCertificate string `protobuf:"bytes,2,opt,name=packageCertificate,proto3" json:"packageCertificate,omitempty"` // HEX string in UPPER case 238 | GoogleAPIKey string `protobuf:"bytes,3,opt,name=googleAPIKey,proto3" json:"googleAPIKey,omitempty"` // Some string, typically starts with "AIza" 239 | FirebaseProjectID string `protobuf:"bytes,4,opt,name=firebaseProjectID,proto3" json:"firebaseProjectID,omitempty"` // some string identifier equal to what the project ID is in Firebase Console 240 | NotificationSenderID string `protobuf:"bytes,5,opt,name=notificationSenderID,proto3" json:"notificationSenderID,omitempty"` // int string 241 | GMPAppID string `protobuf:"bytes,6,opt,name=GMPAppID,proto3" json:"GMPAppID,omitempty"` // 1:NotificationSenderID:android:SOME_ID 242 | AppVersion string `protobuf:"bytes,7,opt,name=AppVersion,proto3" json:"AppVersion,omitempty"` // Major.Minor.Micro 243 | AppVersionWithBuild string `protobuf:"bytes,8,opt,name=AppVersionWithBuild,proto3" json:"AppVersionWithBuild,omitempty"` // Similar to AppVersion but without periods and also build number appended 244 | AuthVersion string `protobuf:"bytes,9,opt,name=authVersion,proto3" json:"authVersion,omitempty"` // Always FIS_v2 245 | SdkVersion string `protobuf:"bytes,10,opt,name=sdkVersion,proto3" json:"sdkVersion,omitempty"` // This can vary between apps 246 | AppNameHash string `protobuf:"bytes,11,opt,name=appNameHash,proto3" json:"appNameHash,omitempty"` 247 | } 248 | 249 | func (x *FirebaseAppData) Reset() { 250 | *x = FirebaseAppData{} 251 | if protoimpl.UnsafeEnabled { 252 | mi := &file_gaf_proto_msgTypes[3] 253 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 254 | ms.StoreMessageInfo(mi) 255 | } 256 | } 257 | 258 | func (x *FirebaseAppData) String() string { 259 | return protoimpl.X.MessageStringOf(x) 260 | } 261 | 262 | func (*FirebaseAppData) ProtoMessage() {} 263 | 264 | func (x *FirebaseAppData) ProtoReflect() protoreflect.Message { 265 | mi := &file_gaf_proto_msgTypes[3] 266 | if protoimpl.UnsafeEnabled && x != nil { 267 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 268 | if ms.LoadMessageInfo() == nil { 269 | ms.StoreMessageInfo(mi) 270 | } 271 | return ms 272 | } 273 | return mi.MessageOf(x) 274 | } 275 | 276 | // Deprecated: Use FirebaseAppData.ProtoReflect.Descriptor instead. 277 | func (*FirebaseAppData) Descriptor() ([]byte, []int) { 278 | return file_gaf_proto_rawDescGZIP(), []int{3} 279 | } 280 | 281 | func (x *FirebaseAppData) GetPackageID() string { 282 | if x != nil { 283 | return x.PackageID 284 | } 285 | return "" 286 | } 287 | 288 | func (x *FirebaseAppData) GetPackageCertificate() string { 289 | if x != nil { 290 | return x.PackageCertificate 291 | } 292 | return "" 293 | } 294 | 295 | func (x *FirebaseAppData) GetGoogleAPIKey() string { 296 | if x != nil { 297 | return x.GoogleAPIKey 298 | } 299 | return "" 300 | } 301 | 302 | func (x *FirebaseAppData) GetFirebaseProjectID() string { 303 | if x != nil { 304 | return x.FirebaseProjectID 305 | } 306 | return "" 307 | } 308 | 309 | func (x *FirebaseAppData) GetNotificationSenderID() string { 310 | if x != nil { 311 | return x.NotificationSenderID 312 | } 313 | return "" 314 | } 315 | 316 | func (x *FirebaseAppData) GetGMPAppID() string { 317 | if x != nil { 318 | return x.GMPAppID 319 | } 320 | return "" 321 | } 322 | 323 | func (x *FirebaseAppData) GetAppVersion() string { 324 | if x != nil { 325 | return x.AppVersion 326 | } 327 | return "" 328 | } 329 | 330 | func (x *FirebaseAppData) GetAppVersionWithBuild() string { 331 | if x != nil { 332 | return x.AppVersionWithBuild 333 | } 334 | return "" 335 | } 336 | 337 | func (x *FirebaseAppData) GetAuthVersion() string { 338 | if x != nil { 339 | return x.AuthVersion 340 | } 341 | return "" 342 | } 343 | 344 | func (x *FirebaseAppData) GetSdkVersion() string { 345 | if x != nil { 346 | return x.SdkVersion 347 | } 348 | return "" 349 | } 350 | 351 | func (x *FirebaseAppData) GetAppNameHash() string { 352 | if x != nil { 353 | return x.AppNameHash 354 | } 355 | return "" 356 | } 357 | 358 | type FirebaseDevice struct { 359 | state protoimpl.MessageState 360 | sizeCache protoimpl.SizeCache 361 | unknownFields protoimpl.UnknownFields 362 | 363 | Device *go_android_utils.Device `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` 364 | CheckinAndroidID int64 `protobuf:"varint,2,opt,name=checkinAndroidID,proto3" json:"checkinAndroidID,omitempty"` 365 | CheckinSecurityToken uint64 `protobuf:"varint,3,opt,name=checkinSecurityToken,proto3" json:"checkinSecurityToken,omitempty"` 366 | // app Package ID : auth Obj 367 | FirebaseInstallations map[string]*FirebaseInstallationData `protobuf:"bytes,4,rep,name=firebaseInstallations,proto3" json:"firebaseInstallations,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 368 | MTalkLastPersistentId string `protobuf:"bytes,5,opt,name=mTalkLastPersistentId,proto3" json:"mTalkLastPersistentId,omitempty"` 369 | FirebaseClientVersion string `protobuf:"bytes,6,opt,name=firebaseClientVersion,proto3" json:"firebaseClientVersion,omitempty"` 370 | GmsVersion string `protobuf:"bytes,7,opt,name=gmsVersion,proto3" json:"gmsVersion,omitempty"` 371 | MTalkPrivateKey string `protobuf:"bytes,8,opt,name=mTalkPrivateKey,proto3" json:"mTalkPrivateKey,omitempty"` 372 | MTalkPublicKey string `protobuf:"bytes,9,opt,name=mTalkPublicKey,proto3" json:"mTalkPublicKey,omitempty"` 373 | MTalkAuthSecret string `protobuf:"bytes,10,opt,name=mTalkAuthSecret,proto3" json:"mTalkAuthSecret,omitempty"` 374 | } 375 | 376 | func (x *FirebaseDevice) Reset() { 377 | *x = FirebaseDevice{} 378 | if protoimpl.UnsafeEnabled { 379 | mi := &file_gaf_proto_msgTypes[4] 380 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 381 | ms.StoreMessageInfo(mi) 382 | } 383 | } 384 | 385 | func (x *FirebaseDevice) String() string { 386 | return protoimpl.X.MessageStringOf(x) 387 | } 388 | 389 | func (*FirebaseDevice) ProtoMessage() {} 390 | 391 | func (x *FirebaseDevice) ProtoReflect() protoreflect.Message { 392 | mi := &file_gaf_proto_msgTypes[4] 393 | if protoimpl.UnsafeEnabled && x != nil { 394 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 395 | if ms.LoadMessageInfo() == nil { 396 | ms.StoreMessageInfo(mi) 397 | } 398 | return ms 399 | } 400 | return mi.MessageOf(x) 401 | } 402 | 403 | // Deprecated: Use FirebaseDevice.ProtoReflect.Descriptor instead. 404 | func (*FirebaseDevice) Descriptor() ([]byte, []int) { 405 | return file_gaf_proto_rawDescGZIP(), []int{4} 406 | } 407 | 408 | func (x *FirebaseDevice) GetDevice() *go_android_utils.Device { 409 | if x != nil { 410 | return x.Device 411 | } 412 | return nil 413 | } 414 | 415 | func (x *FirebaseDevice) GetCheckinAndroidID() int64 { 416 | if x != nil { 417 | return x.CheckinAndroidID 418 | } 419 | return 0 420 | } 421 | 422 | func (x *FirebaseDevice) GetCheckinSecurityToken() uint64 { 423 | if x != nil { 424 | return x.CheckinSecurityToken 425 | } 426 | return 0 427 | } 428 | 429 | func (x *FirebaseDevice) GetFirebaseInstallations() map[string]*FirebaseInstallationData { 430 | if x != nil { 431 | return x.FirebaseInstallations 432 | } 433 | return nil 434 | } 435 | 436 | func (x *FirebaseDevice) GetMTalkLastPersistentId() string { 437 | if x != nil { 438 | return x.MTalkLastPersistentId 439 | } 440 | return "" 441 | } 442 | 443 | func (x *FirebaseDevice) GetFirebaseClientVersion() string { 444 | if x != nil { 445 | return x.FirebaseClientVersion 446 | } 447 | return "" 448 | } 449 | 450 | func (x *FirebaseDevice) GetGmsVersion() string { 451 | if x != nil { 452 | return x.GmsVersion 453 | } 454 | return "" 455 | } 456 | 457 | func (x *FirebaseDevice) GetMTalkPrivateKey() string { 458 | if x != nil { 459 | return x.MTalkPrivateKey 460 | } 461 | return "" 462 | } 463 | 464 | func (x *FirebaseDevice) GetMTalkPublicKey() string { 465 | if x != nil { 466 | return x.MTalkPublicKey 467 | } 468 | return "" 469 | } 470 | 471 | func (x *FirebaseDevice) GetMTalkAuthSecret() string { 472 | if x != nil { 473 | return x.MTalkAuthSecret 474 | } 475 | return "" 476 | } 477 | 478 | var File_gaf_proto protoreflect.FileDescriptor 479 | 480 | var file_gaf_proto_rawDesc = []byte{ 481 | 0x0a, 0x09, 0x67, 0x61, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x61, 0x6e, 0x64, 482 | 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x1a, 0x1f, 0x67, 483 | 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 484 | 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 485 | 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 486 | 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x16, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 487 | 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 488 | 0x0a, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 489 | 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 490 | 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 491 | 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 492 | 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 493 | 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 494 | 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 495 | 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x69, 0x64, 496 | 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x64, 0x54, 497 | 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x9e, 0x01, 0x0a, 0x18, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 498 | 0x65, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 499 | 0x61, 0x12, 0x2c, 0x0a, 0x11, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 500 | 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x6e, 0x6f, 501 | 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 502 | 0x1e, 0x0a, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 503 | 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 504 | 0x1c, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 505 | 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 506 | 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 507 | 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0x94, 0x02, 0x0a, 0x18, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 508 | 0x73, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 509 | 0x74, 0x61, 0x12, 0x36, 0x0a, 0x16, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x49, 0x6e, 510 | 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 511 | 0x28, 0x09, 0x52, 0x16, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x73, 0x74, 512 | 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x56, 0x0a, 0x10, 0x6e, 0x6f, 513 | 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 514 | 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x66, 515 | 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 516 | 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 517 | 0x52, 0x10, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 518 | 0x74, 0x61, 0x12, 0x68, 0x0a, 0x1a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 519 | 0x6f, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 520 | 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 521 | 0x5f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 522 | 0x73, 0x65, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 523 | 0x52, 0x1a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x41, 0x75, 524 | 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb7, 0x03, 0x0a, 525 | 0x0f, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x41, 0x70, 0x70, 0x44, 0x61, 0x74, 0x61, 526 | 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 527 | 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x49, 0x44, 0x12, 0x2e, 528 | 0x0a, 0x12, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 529 | 0x63, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x61, 0x63, 0x6b, 530 | 0x61, 0x67, 0x65, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x22, 531 | 0x0a, 0x0c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x50, 0x49, 0x4b, 0x65, 0x79, 0x18, 0x03, 532 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x41, 0x50, 0x49, 0x4b, 533 | 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x50, 0x72, 534 | 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x66, 535 | 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x44, 536 | 0x12, 0x32, 0x0a, 0x14, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 537 | 0x53, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x14, 538 | 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x6e, 0x64, 539 | 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x47, 0x4d, 0x50, 0x41, 0x70, 0x70, 0x49, 0x44, 540 | 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x47, 0x4d, 0x50, 0x41, 0x70, 0x70, 0x49, 0x44, 541 | 0x12, 0x1e, 0x0a, 0x0a, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 542 | 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 543 | 0x12, 0x30, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x57, 0x69, 544 | 0x74, 0x68, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x41, 545 | 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x57, 0x69, 0x74, 0x68, 0x42, 0x75, 0x69, 546 | 0x6c, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 547 | 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x56, 0x65, 0x72, 548 | 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x64, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 549 | 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x64, 0x6b, 0x56, 0x65, 0x72, 550 | 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x48, 551 | 0x61, 0x73, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x70, 0x70, 0x4e, 0x61, 552 | 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x22, 0x90, 0x05, 0x0a, 0x0e, 0x46, 0x69, 0x72, 0x65, 0x62, 553 | 0x61, 0x73, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x64, 0x65, 0x76, 554 | 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x6e, 0x64, 0x72, 555 | 0x6f, 0x69, 0x64, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x73, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 556 | 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x68, 0x65, 0x63, 557 | 0x6b, 0x69, 0x6e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 558 | 0x28, 0x03, 0x52, 0x10, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x41, 0x6e, 0x64, 0x72, 0x6f, 559 | 0x69, 0x64, 0x49, 0x44, 0x12, 0x32, 0x0a, 0x14, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x53, 560 | 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 561 | 0x28, 0x04, 0x52, 0x14, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x69, 0x6e, 0x53, 0x65, 0x63, 0x75, 0x72, 562 | 0x69, 0x74, 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x71, 0x0a, 0x15, 0x66, 0x69, 0x72, 0x65, 563 | 0x62, 0x61, 0x73, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 564 | 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 565 | 0x64, 0x5f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 566 | 0x61, 0x73, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 567 | 0x73, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 568 | 0x6e, 0x74, 0x72, 0x79, 0x52, 0x15, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x49, 0x6e, 569 | 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x6d, 570 | 0x54, 0x61, 0x6c, 0x6b, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 571 | 0x6e, 0x74, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6d, 0x54, 0x61, 0x6c, 572 | 0x6b, 0x4c, 0x61, 0x73, 0x74, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x49, 573 | 0x64, 0x12, 0x34, 0x0a, 0x15, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6c, 0x69, 574 | 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 575 | 0x52, 0x15, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 576 | 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x6d, 0x73, 0x56, 0x65, 577 | 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x67, 0x6d, 0x73, 578 | 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x54, 0x61, 0x6c, 0x6b, 579 | 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 580 | 0x52, 0x0f, 0x6d, 0x54, 0x61, 0x6c, 0x6b, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 581 | 0x79, 0x12, 0x26, 0x0a, 0x0e, 0x6d, 0x54, 0x61, 0x6c, 0x6b, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 582 | 0x4b, 0x65, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x54, 0x61, 0x6c, 0x6b, 583 | 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x6d, 0x54, 0x61, 584 | 0x6c, 0x6b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x0a, 0x20, 0x01, 585 | 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x54, 0x61, 0x6c, 0x6b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 586 | 0x72, 0x65, 0x74, 0x1a, 0x74, 0x0a, 0x1a, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x49, 587 | 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 588 | 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 589 | 0x6b, 0x65, 0x79, 0x12, 0x40, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 590 | 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x5f, 0x66, 0x69, 0x72, 591 | 0x65, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x46, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x49, 0x6e, 592 | 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x05, 593 | 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 594 | 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x42, 0x52, 0x55, 0x48, 0x49, 0x74, 0x73, 0x41, 595 | 0x42, 0x75, 0x6e, 0x6e, 0x79, 0x2f, 0x67, 0x6f, 0x2d, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 596 | 0x2d, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x66, 0x69, 0x72, 0x65, 0x62, 0x61, 597 | 0x73, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 598 | } 599 | 600 | var ( 601 | file_gaf_proto_rawDescOnce sync.Once 602 | file_gaf_proto_rawDescData = file_gaf_proto_rawDesc 603 | ) 604 | 605 | func file_gaf_proto_rawDescGZIP() []byte { 606 | file_gaf_proto_rawDescOnce.Do(func() { 607 | file_gaf_proto_rawDescData = protoimpl.X.CompressGZIP(file_gaf_proto_rawDescData) 608 | }) 609 | return file_gaf_proto_rawDescData 610 | } 611 | 612 | var file_gaf_proto_msgTypes = make([]protoimpl.MessageInfo, 6) 613 | var file_gaf_proto_goTypes = []interface{}{ 614 | (*FirebaseAuthentication)(nil), // 0: android_firebase.FirebaseAuthentication 615 | (*FirebaseNotificationData)(nil), // 1: android_firebase.FirebaseNotificationData 616 | (*FirebaseInstallationData)(nil), // 2: android_firebase.FirebaseInstallationData 617 | (*FirebaseAppData)(nil), // 3: android_firebase.FirebaseAppData 618 | (*FirebaseDevice)(nil), // 4: android_firebase.FirebaseDevice 619 | nil, // 5: android_firebase.FirebaseDevice.FirebaseInstallationsEntry 620 | (*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp 621 | (*go_android_utils.Device)(nil), // 7: android_utils.Device 622 | } 623 | var file_gaf_proto_depIdxs = []int32{ 624 | 6, // 0: android_firebase.FirebaseAuthentication.expires:type_name -> google.protobuf.Timestamp 625 | 1, // 1: android_firebase.FirebaseInstallationData.notificationData:type_name -> android_firebase.FirebaseNotificationData 626 | 0, // 2: android_firebase.FirebaseInstallationData.installationAuthentication:type_name -> android_firebase.FirebaseAuthentication 627 | 7, // 3: android_firebase.FirebaseDevice.device:type_name -> android_utils.Device 628 | 5, // 4: android_firebase.FirebaseDevice.firebaseInstallations:type_name -> android_firebase.FirebaseDevice.FirebaseInstallationsEntry 629 | 2, // 5: android_firebase.FirebaseDevice.FirebaseInstallationsEntry.value:type_name -> android_firebase.FirebaseInstallationData 630 | 6, // [6:6] is the sub-list for method output_type 631 | 6, // [6:6] is the sub-list for method input_type 632 | 6, // [6:6] is the sub-list for extension type_name 633 | 6, // [6:6] is the sub-list for extension extendee 634 | 0, // [0:6] is the sub-list for field type_name 635 | } 636 | 637 | func init() { file_gaf_proto_init() } 638 | func file_gaf_proto_init() { 639 | if File_gaf_proto != nil { 640 | return 641 | } 642 | if !protoimpl.UnsafeEnabled { 643 | file_gaf_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 644 | switch v := v.(*FirebaseAuthentication); i { 645 | case 0: 646 | return &v.state 647 | case 1: 648 | return &v.sizeCache 649 | case 2: 650 | return &v.unknownFields 651 | default: 652 | return nil 653 | } 654 | } 655 | file_gaf_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 656 | switch v := v.(*FirebaseNotificationData); i { 657 | case 0: 658 | return &v.state 659 | case 1: 660 | return &v.sizeCache 661 | case 2: 662 | return &v.unknownFields 663 | default: 664 | return nil 665 | } 666 | } 667 | file_gaf_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 668 | switch v := v.(*FirebaseInstallationData); i { 669 | case 0: 670 | return &v.state 671 | case 1: 672 | return &v.sizeCache 673 | case 2: 674 | return &v.unknownFields 675 | default: 676 | return nil 677 | } 678 | } 679 | file_gaf_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 680 | switch v := v.(*FirebaseAppData); i { 681 | case 0: 682 | return &v.state 683 | case 1: 684 | return &v.sizeCache 685 | case 2: 686 | return &v.unknownFields 687 | default: 688 | return nil 689 | } 690 | } 691 | file_gaf_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { 692 | switch v := v.(*FirebaseDevice); i { 693 | case 0: 694 | return &v.state 695 | case 1: 696 | return &v.sizeCache 697 | case 2: 698 | return &v.unknownFields 699 | default: 700 | return nil 701 | } 702 | } 703 | } 704 | type x struct{} 705 | out := protoimpl.TypeBuilder{ 706 | File: protoimpl.DescBuilder{ 707 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 708 | RawDescriptor: file_gaf_proto_rawDesc, 709 | NumEnums: 0, 710 | NumMessages: 6, 711 | NumExtensions: 0, 712 | NumServices: 0, 713 | }, 714 | GoTypes: file_gaf_proto_goTypes, 715 | DependencyIndexes: file_gaf_proto_depIdxs, 716 | MessageInfos: file_gaf_proto_msgTypes, 717 | }.Build() 718 | File_gaf_proto = out.File 719 | file_gaf_proto_rawDesc = nil 720 | file_gaf_proto_goTypes = nil 721 | file_gaf_proto_depIdxs = nil 722 | } 723 | -------------------------------------------------------------------------------- /api/gaf.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package android_firebase; 3 | option go_package = "github.com/BRUHItsABunny/go-android-firebase/firebase_api"; 4 | 5 | import "google/protobuf/timestamp.proto"; 6 | import "android_proto.proto"; 7 | 8 | message FirebaseAuthentication { 9 | string accessToken = 1; 10 | google.protobuf.Timestamp expires = 2; 11 | string refreshToken = 3; 12 | string idToken = 4; 13 | } 14 | 15 | message FirebaseNotificationData { 16 | string notificationToken = 1; 17 | // The fields below are needed for Chromium push notification, not for native Android apps (typically) 18 | bytes privateKey = 2; 19 | bytes publicKey = 3; 20 | bytes secret = 4; 21 | } 22 | 23 | message FirebaseInstallationData { 24 | string FirebaseInstallationID = 1; 25 | FirebaseNotificationData notificationData = 2; 26 | FirebaseAuthentication installationAuthentication = 3; // Upon NotifyInstall 27 | // TODO: Support more authentication? 28 | } 29 | 30 | message FirebaseAppData { 31 | string packageID = 1; // com.app.my 32 | string packageCertificate = 2; // HEX string in UPPER case 33 | string googleAPIKey = 3; // Some string, typically starts with "AIza" 34 | string firebaseProjectID = 4; // some string identifier equal to what the project ID is in Firebase Console 35 | string notificationSenderID = 5; // int string 36 | string GMPAppID = 6; // 1:NotificationSenderID:android:SOME_ID 37 | string AppVersion = 7; // Major.Minor.Micro 38 | string AppVersionWithBuild = 8; // Similar to AppVersion but without periods and also build number appended 39 | string authVersion = 9; // Always FIS_v2 40 | string sdkVersion = 10; // This can vary between apps 41 | string appNameHash = 11; 42 | } 43 | 44 | message FirebaseDevice { 45 | android_utils.Device device = 1; 46 | int64 checkinAndroidID = 2; 47 | uint64 checkinSecurityToken = 3; 48 | // app Package ID : auth Obj 49 | map firebaseInstallations = 4; 50 | string mTalkLastPersistentId = 5; 51 | string firebaseClientVersion = 6; 52 | string gmsVersion = 7; 53 | string mTalkPrivateKey = 8; 54 | string mTalkPublicKey = 9; 55 | string mTalkAuthSecret = 10; 56 | } 57 | 58 | -------------------------------------------------------------------------------- /api/gaf_vtproto.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-vtproto. DO NOT EDIT. 2 | // protoc-gen-go-vtproto version: v0.2.1-0.20220224152539-d8520340f573 3 | // source: gaf.proto 4 | 5 | package firebase_api 6 | 7 | import ( 8 | fmt "fmt" 9 | go_android_utils "github.com/BRUHItsABunny/go-android-utils" 10 | proto "google.golang.org/protobuf/proto" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | timestamppb "google.golang.org/protobuf/types/known/timestamppb" 13 | io "io" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | func (m *FirebaseAuthentication) MarshalVT() (dAtA []byte, err error) { 24 | if m == nil { 25 | return nil, nil 26 | } 27 | size := m.SizeVT() 28 | dAtA = make([]byte, size) 29 | n, err := m.MarshalToSizedBufferVT(dAtA[:size]) 30 | if err != nil { 31 | return nil, err 32 | } 33 | return dAtA[:n], nil 34 | } 35 | 36 | func (m *FirebaseAuthentication) MarshalToVT(dAtA []byte) (int, error) { 37 | size := m.SizeVT() 38 | return m.MarshalToSizedBufferVT(dAtA[:size]) 39 | } 40 | 41 | func (m *FirebaseAuthentication) MarshalToSizedBufferVT(dAtA []byte) (int, error) { 42 | if m == nil { 43 | return 0, nil 44 | } 45 | i := len(dAtA) 46 | _ = i 47 | var l int 48 | _ = l 49 | if m.unknownFields != nil { 50 | i -= len(m.unknownFields) 51 | copy(dAtA[i:], m.unknownFields) 52 | } 53 | if len(m.IdToken) > 0 { 54 | i -= len(m.IdToken) 55 | copy(dAtA[i:], m.IdToken) 56 | i = encodeVarint(dAtA, i, uint64(len(m.IdToken))) 57 | i-- 58 | dAtA[i] = 0x22 59 | } 60 | if len(m.RefreshToken) > 0 { 61 | i -= len(m.RefreshToken) 62 | copy(dAtA[i:], m.RefreshToken) 63 | i = encodeVarint(dAtA, i, uint64(len(m.RefreshToken))) 64 | i-- 65 | dAtA[i] = 0x1a 66 | } 67 | if m.Expires != nil { 68 | if marshalto, ok := interface{}(m.Expires).(interface { 69 | MarshalToSizedBufferVT([]byte) (int, error) 70 | }); ok { 71 | size, err := marshalto.MarshalToSizedBufferVT(dAtA[:i]) 72 | if err != nil { 73 | return 0, err 74 | } 75 | i -= size 76 | i = encodeVarint(dAtA, i, uint64(size)) 77 | } else { 78 | encoded, err := proto.Marshal(m.Expires) 79 | if err != nil { 80 | return 0, err 81 | } 82 | i -= len(encoded) 83 | copy(dAtA[i:], encoded) 84 | i = encodeVarint(dAtA, i, uint64(len(encoded))) 85 | } 86 | i-- 87 | dAtA[i] = 0x12 88 | } 89 | if len(m.AccessToken) > 0 { 90 | i -= len(m.AccessToken) 91 | copy(dAtA[i:], m.AccessToken) 92 | i = encodeVarint(dAtA, i, uint64(len(m.AccessToken))) 93 | i-- 94 | dAtA[i] = 0xa 95 | } 96 | return len(dAtA) - i, nil 97 | } 98 | 99 | func (m *FirebaseNotificationData) MarshalVT() (dAtA []byte, err error) { 100 | if m == nil { 101 | return nil, nil 102 | } 103 | size := m.SizeVT() 104 | dAtA = make([]byte, size) 105 | n, err := m.MarshalToSizedBufferVT(dAtA[:size]) 106 | if err != nil { 107 | return nil, err 108 | } 109 | return dAtA[:n], nil 110 | } 111 | 112 | func (m *FirebaseNotificationData) MarshalToVT(dAtA []byte) (int, error) { 113 | size := m.SizeVT() 114 | return m.MarshalToSizedBufferVT(dAtA[:size]) 115 | } 116 | 117 | func (m *FirebaseNotificationData) MarshalToSizedBufferVT(dAtA []byte) (int, error) { 118 | if m == nil { 119 | return 0, nil 120 | } 121 | i := len(dAtA) 122 | _ = i 123 | var l int 124 | _ = l 125 | if m.unknownFields != nil { 126 | i -= len(m.unknownFields) 127 | copy(dAtA[i:], m.unknownFields) 128 | } 129 | if len(m.Secret) > 0 { 130 | i -= len(m.Secret) 131 | copy(dAtA[i:], m.Secret) 132 | i = encodeVarint(dAtA, i, uint64(len(m.Secret))) 133 | i-- 134 | dAtA[i] = 0x22 135 | } 136 | if len(m.PublicKey) > 0 { 137 | i -= len(m.PublicKey) 138 | copy(dAtA[i:], m.PublicKey) 139 | i = encodeVarint(dAtA, i, uint64(len(m.PublicKey))) 140 | i-- 141 | dAtA[i] = 0x1a 142 | } 143 | if len(m.PrivateKey) > 0 { 144 | i -= len(m.PrivateKey) 145 | copy(dAtA[i:], m.PrivateKey) 146 | i = encodeVarint(dAtA, i, uint64(len(m.PrivateKey))) 147 | i-- 148 | dAtA[i] = 0x12 149 | } 150 | if len(m.NotificationToken) > 0 { 151 | i -= len(m.NotificationToken) 152 | copy(dAtA[i:], m.NotificationToken) 153 | i = encodeVarint(dAtA, i, uint64(len(m.NotificationToken))) 154 | i-- 155 | dAtA[i] = 0xa 156 | } 157 | return len(dAtA) - i, nil 158 | } 159 | 160 | func (m *FirebaseInstallationData) MarshalVT() (dAtA []byte, err error) { 161 | if m == nil { 162 | return nil, nil 163 | } 164 | size := m.SizeVT() 165 | dAtA = make([]byte, size) 166 | n, err := m.MarshalToSizedBufferVT(dAtA[:size]) 167 | if err != nil { 168 | return nil, err 169 | } 170 | return dAtA[:n], nil 171 | } 172 | 173 | func (m *FirebaseInstallationData) MarshalToVT(dAtA []byte) (int, error) { 174 | size := m.SizeVT() 175 | return m.MarshalToSizedBufferVT(dAtA[:size]) 176 | } 177 | 178 | func (m *FirebaseInstallationData) MarshalToSizedBufferVT(dAtA []byte) (int, error) { 179 | if m == nil { 180 | return 0, nil 181 | } 182 | i := len(dAtA) 183 | _ = i 184 | var l int 185 | _ = l 186 | if m.unknownFields != nil { 187 | i -= len(m.unknownFields) 188 | copy(dAtA[i:], m.unknownFields) 189 | } 190 | if m.InstallationAuthentication != nil { 191 | size, err := m.InstallationAuthentication.MarshalToSizedBufferVT(dAtA[:i]) 192 | if err != nil { 193 | return 0, err 194 | } 195 | i -= size 196 | i = encodeVarint(dAtA, i, uint64(size)) 197 | i-- 198 | dAtA[i] = 0x1a 199 | } 200 | if m.NotificationData != nil { 201 | size, err := m.NotificationData.MarshalToSizedBufferVT(dAtA[:i]) 202 | if err != nil { 203 | return 0, err 204 | } 205 | i -= size 206 | i = encodeVarint(dAtA, i, uint64(size)) 207 | i-- 208 | dAtA[i] = 0x12 209 | } 210 | if len(m.FirebaseInstallationID) > 0 { 211 | i -= len(m.FirebaseInstallationID) 212 | copy(dAtA[i:], m.FirebaseInstallationID) 213 | i = encodeVarint(dAtA, i, uint64(len(m.FirebaseInstallationID))) 214 | i-- 215 | dAtA[i] = 0xa 216 | } 217 | return len(dAtA) - i, nil 218 | } 219 | 220 | func (m *FirebaseAppData) MarshalVT() (dAtA []byte, err error) { 221 | if m == nil { 222 | return nil, nil 223 | } 224 | size := m.SizeVT() 225 | dAtA = make([]byte, size) 226 | n, err := m.MarshalToSizedBufferVT(dAtA[:size]) 227 | if err != nil { 228 | return nil, err 229 | } 230 | return dAtA[:n], nil 231 | } 232 | 233 | func (m *FirebaseAppData) MarshalToVT(dAtA []byte) (int, error) { 234 | size := m.SizeVT() 235 | return m.MarshalToSizedBufferVT(dAtA[:size]) 236 | } 237 | 238 | func (m *FirebaseAppData) MarshalToSizedBufferVT(dAtA []byte) (int, error) { 239 | if m == nil { 240 | return 0, nil 241 | } 242 | i := len(dAtA) 243 | _ = i 244 | var l int 245 | _ = l 246 | if m.unknownFields != nil { 247 | i -= len(m.unknownFields) 248 | copy(dAtA[i:], m.unknownFields) 249 | } 250 | if len(m.AppNameHash) > 0 { 251 | i -= len(m.AppNameHash) 252 | copy(dAtA[i:], m.AppNameHash) 253 | i = encodeVarint(dAtA, i, uint64(len(m.AppNameHash))) 254 | i-- 255 | dAtA[i] = 0x5a 256 | } 257 | if len(m.SdkVersion) > 0 { 258 | i -= len(m.SdkVersion) 259 | copy(dAtA[i:], m.SdkVersion) 260 | i = encodeVarint(dAtA, i, uint64(len(m.SdkVersion))) 261 | i-- 262 | dAtA[i] = 0x52 263 | } 264 | if len(m.AuthVersion) > 0 { 265 | i -= len(m.AuthVersion) 266 | copy(dAtA[i:], m.AuthVersion) 267 | i = encodeVarint(dAtA, i, uint64(len(m.AuthVersion))) 268 | i-- 269 | dAtA[i] = 0x4a 270 | } 271 | if len(m.AppVersionWithBuild) > 0 { 272 | i -= len(m.AppVersionWithBuild) 273 | copy(dAtA[i:], m.AppVersionWithBuild) 274 | i = encodeVarint(dAtA, i, uint64(len(m.AppVersionWithBuild))) 275 | i-- 276 | dAtA[i] = 0x42 277 | } 278 | if len(m.AppVersion) > 0 { 279 | i -= len(m.AppVersion) 280 | copy(dAtA[i:], m.AppVersion) 281 | i = encodeVarint(dAtA, i, uint64(len(m.AppVersion))) 282 | i-- 283 | dAtA[i] = 0x3a 284 | } 285 | if len(m.GMPAppID) > 0 { 286 | i -= len(m.GMPAppID) 287 | copy(dAtA[i:], m.GMPAppID) 288 | i = encodeVarint(dAtA, i, uint64(len(m.GMPAppID))) 289 | i-- 290 | dAtA[i] = 0x32 291 | } 292 | if len(m.NotificationSenderID) > 0 { 293 | i -= len(m.NotificationSenderID) 294 | copy(dAtA[i:], m.NotificationSenderID) 295 | i = encodeVarint(dAtA, i, uint64(len(m.NotificationSenderID))) 296 | i-- 297 | dAtA[i] = 0x2a 298 | } 299 | if len(m.FirebaseProjectID) > 0 { 300 | i -= len(m.FirebaseProjectID) 301 | copy(dAtA[i:], m.FirebaseProjectID) 302 | i = encodeVarint(dAtA, i, uint64(len(m.FirebaseProjectID))) 303 | i-- 304 | dAtA[i] = 0x22 305 | } 306 | if len(m.GoogleAPIKey) > 0 { 307 | i -= len(m.GoogleAPIKey) 308 | copy(dAtA[i:], m.GoogleAPIKey) 309 | i = encodeVarint(dAtA, i, uint64(len(m.GoogleAPIKey))) 310 | i-- 311 | dAtA[i] = 0x1a 312 | } 313 | if len(m.PackageCertificate) > 0 { 314 | i -= len(m.PackageCertificate) 315 | copy(dAtA[i:], m.PackageCertificate) 316 | i = encodeVarint(dAtA, i, uint64(len(m.PackageCertificate))) 317 | i-- 318 | dAtA[i] = 0x12 319 | } 320 | if len(m.PackageID) > 0 { 321 | i -= len(m.PackageID) 322 | copy(dAtA[i:], m.PackageID) 323 | i = encodeVarint(dAtA, i, uint64(len(m.PackageID))) 324 | i-- 325 | dAtA[i] = 0xa 326 | } 327 | return len(dAtA) - i, nil 328 | } 329 | 330 | func (m *FirebaseDevice) MarshalVT() (dAtA []byte, err error) { 331 | if m == nil { 332 | return nil, nil 333 | } 334 | size := m.SizeVT() 335 | dAtA = make([]byte, size) 336 | n, err := m.MarshalToSizedBufferVT(dAtA[:size]) 337 | if err != nil { 338 | return nil, err 339 | } 340 | return dAtA[:n], nil 341 | } 342 | 343 | func (m *FirebaseDevice) MarshalToVT(dAtA []byte) (int, error) { 344 | size := m.SizeVT() 345 | return m.MarshalToSizedBufferVT(dAtA[:size]) 346 | } 347 | 348 | func (m *FirebaseDevice) MarshalToSizedBufferVT(dAtA []byte) (int, error) { 349 | if m == nil { 350 | return 0, nil 351 | } 352 | i := len(dAtA) 353 | _ = i 354 | var l int 355 | _ = l 356 | if m.unknownFields != nil { 357 | i -= len(m.unknownFields) 358 | copy(dAtA[i:], m.unknownFields) 359 | } 360 | if len(m.MTalkAuthSecret) > 0 { 361 | i -= len(m.MTalkAuthSecret) 362 | copy(dAtA[i:], m.MTalkAuthSecret) 363 | i = encodeVarint(dAtA, i, uint64(len(m.MTalkAuthSecret))) 364 | i-- 365 | dAtA[i] = 0x52 366 | } 367 | if len(m.MTalkPublicKey) > 0 { 368 | i -= len(m.MTalkPublicKey) 369 | copy(dAtA[i:], m.MTalkPublicKey) 370 | i = encodeVarint(dAtA, i, uint64(len(m.MTalkPublicKey))) 371 | i-- 372 | dAtA[i] = 0x4a 373 | } 374 | if len(m.MTalkPrivateKey) > 0 { 375 | i -= len(m.MTalkPrivateKey) 376 | copy(dAtA[i:], m.MTalkPrivateKey) 377 | i = encodeVarint(dAtA, i, uint64(len(m.MTalkPrivateKey))) 378 | i-- 379 | dAtA[i] = 0x42 380 | } 381 | if len(m.GmsVersion) > 0 { 382 | i -= len(m.GmsVersion) 383 | copy(dAtA[i:], m.GmsVersion) 384 | i = encodeVarint(dAtA, i, uint64(len(m.GmsVersion))) 385 | i-- 386 | dAtA[i] = 0x3a 387 | } 388 | if len(m.FirebaseClientVersion) > 0 { 389 | i -= len(m.FirebaseClientVersion) 390 | copy(dAtA[i:], m.FirebaseClientVersion) 391 | i = encodeVarint(dAtA, i, uint64(len(m.FirebaseClientVersion))) 392 | i-- 393 | dAtA[i] = 0x32 394 | } 395 | if len(m.MTalkLastPersistentId) > 0 { 396 | i -= len(m.MTalkLastPersistentId) 397 | copy(dAtA[i:], m.MTalkLastPersistentId) 398 | i = encodeVarint(dAtA, i, uint64(len(m.MTalkLastPersistentId))) 399 | i-- 400 | dAtA[i] = 0x2a 401 | } 402 | if len(m.FirebaseInstallations) > 0 { 403 | for k := range m.FirebaseInstallations { 404 | v := m.FirebaseInstallations[k] 405 | baseI := i 406 | size, err := v.MarshalToSizedBufferVT(dAtA[:i]) 407 | if err != nil { 408 | return 0, err 409 | } 410 | i -= size 411 | i = encodeVarint(dAtA, i, uint64(size)) 412 | i-- 413 | dAtA[i] = 0x12 414 | i -= len(k) 415 | copy(dAtA[i:], k) 416 | i = encodeVarint(dAtA, i, uint64(len(k))) 417 | i-- 418 | dAtA[i] = 0xa 419 | i = encodeVarint(dAtA, i, uint64(baseI-i)) 420 | i-- 421 | dAtA[i] = 0x22 422 | } 423 | } 424 | if m.CheckinSecurityToken != 0 { 425 | i = encodeVarint(dAtA, i, uint64(m.CheckinSecurityToken)) 426 | i-- 427 | dAtA[i] = 0x18 428 | } 429 | if m.CheckinAndroidID != 0 { 430 | i = encodeVarint(dAtA, i, uint64(m.CheckinAndroidID)) 431 | i-- 432 | dAtA[i] = 0x10 433 | } 434 | if m.Device != nil { 435 | if marshalto, ok := interface{}(m.Device).(interface { 436 | MarshalToSizedBufferVT([]byte) (int, error) 437 | }); ok { 438 | size, err := marshalto.MarshalToSizedBufferVT(dAtA[:i]) 439 | if err != nil { 440 | return 0, err 441 | } 442 | i -= size 443 | i = encodeVarint(dAtA, i, uint64(size)) 444 | } else { 445 | encoded, err := proto.Marshal(m.Device) 446 | if err != nil { 447 | return 0, err 448 | } 449 | i -= len(encoded) 450 | copy(dAtA[i:], encoded) 451 | i = encodeVarint(dAtA, i, uint64(len(encoded))) 452 | } 453 | i-- 454 | dAtA[i] = 0xa 455 | } 456 | return len(dAtA) - i, nil 457 | } 458 | 459 | func (m *FirebaseAuthentication) SizeVT() (n int) { 460 | if m == nil { 461 | return 0 462 | } 463 | var l int 464 | _ = l 465 | l = len(m.AccessToken) 466 | if l > 0 { 467 | n += 1 + l + sov(uint64(l)) 468 | } 469 | if m.Expires != nil { 470 | if size, ok := interface{}(m.Expires).(interface { 471 | SizeVT() int 472 | }); ok { 473 | l = size.SizeVT() 474 | } else { 475 | l = proto.Size(m.Expires) 476 | } 477 | n += 1 + l + sov(uint64(l)) 478 | } 479 | l = len(m.RefreshToken) 480 | if l > 0 { 481 | n += 1 + l + sov(uint64(l)) 482 | } 483 | l = len(m.IdToken) 484 | if l > 0 { 485 | n += 1 + l + sov(uint64(l)) 486 | } 487 | if m.unknownFields != nil { 488 | n += len(m.unknownFields) 489 | } 490 | return n 491 | } 492 | 493 | func (m *FirebaseNotificationData) SizeVT() (n int) { 494 | if m == nil { 495 | return 0 496 | } 497 | var l int 498 | _ = l 499 | l = len(m.NotificationToken) 500 | if l > 0 { 501 | n += 1 + l + sov(uint64(l)) 502 | } 503 | l = len(m.PrivateKey) 504 | if l > 0 { 505 | n += 1 + l + sov(uint64(l)) 506 | } 507 | l = len(m.PublicKey) 508 | if l > 0 { 509 | n += 1 + l + sov(uint64(l)) 510 | } 511 | l = len(m.Secret) 512 | if l > 0 { 513 | n += 1 + l + sov(uint64(l)) 514 | } 515 | if m.unknownFields != nil { 516 | n += len(m.unknownFields) 517 | } 518 | return n 519 | } 520 | 521 | func (m *FirebaseInstallationData) SizeVT() (n int) { 522 | if m == nil { 523 | return 0 524 | } 525 | var l int 526 | _ = l 527 | l = len(m.FirebaseInstallationID) 528 | if l > 0 { 529 | n += 1 + l + sov(uint64(l)) 530 | } 531 | if m.NotificationData != nil { 532 | l = m.NotificationData.SizeVT() 533 | n += 1 + l + sov(uint64(l)) 534 | } 535 | if m.InstallationAuthentication != nil { 536 | l = m.InstallationAuthentication.SizeVT() 537 | n += 1 + l + sov(uint64(l)) 538 | } 539 | if m.unknownFields != nil { 540 | n += len(m.unknownFields) 541 | } 542 | return n 543 | } 544 | 545 | func (m *FirebaseAppData) SizeVT() (n int) { 546 | if m == nil { 547 | return 0 548 | } 549 | var l int 550 | _ = l 551 | l = len(m.PackageID) 552 | if l > 0 { 553 | n += 1 + l + sov(uint64(l)) 554 | } 555 | l = len(m.PackageCertificate) 556 | if l > 0 { 557 | n += 1 + l + sov(uint64(l)) 558 | } 559 | l = len(m.GoogleAPIKey) 560 | if l > 0 { 561 | n += 1 + l + sov(uint64(l)) 562 | } 563 | l = len(m.FirebaseProjectID) 564 | if l > 0 { 565 | n += 1 + l + sov(uint64(l)) 566 | } 567 | l = len(m.NotificationSenderID) 568 | if l > 0 { 569 | n += 1 + l + sov(uint64(l)) 570 | } 571 | l = len(m.GMPAppID) 572 | if l > 0 { 573 | n += 1 + l + sov(uint64(l)) 574 | } 575 | l = len(m.AppVersion) 576 | if l > 0 { 577 | n += 1 + l + sov(uint64(l)) 578 | } 579 | l = len(m.AppVersionWithBuild) 580 | if l > 0 { 581 | n += 1 + l + sov(uint64(l)) 582 | } 583 | l = len(m.AuthVersion) 584 | if l > 0 { 585 | n += 1 + l + sov(uint64(l)) 586 | } 587 | l = len(m.SdkVersion) 588 | if l > 0 { 589 | n += 1 + l + sov(uint64(l)) 590 | } 591 | l = len(m.AppNameHash) 592 | if l > 0 { 593 | n += 1 + l + sov(uint64(l)) 594 | } 595 | if m.unknownFields != nil { 596 | n += len(m.unknownFields) 597 | } 598 | return n 599 | } 600 | 601 | func (m *FirebaseDevice) SizeVT() (n int) { 602 | if m == nil { 603 | return 0 604 | } 605 | var l int 606 | _ = l 607 | if m.Device != nil { 608 | if size, ok := interface{}(m.Device).(interface { 609 | SizeVT() int 610 | }); ok { 611 | l = size.SizeVT() 612 | } else { 613 | l = proto.Size(m.Device) 614 | } 615 | n += 1 + l + sov(uint64(l)) 616 | } 617 | if m.CheckinAndroidID != 0 { 618 | n += 1 + sov(uint64(m.CheckinAndroidID)) 619 | } 620 | if m.CheckinSecurityToken != 0 { 621 | n += 1 + sov(uint64(m.CheckinSecurityToken)) 622 | } 623 | if len(m.FirebaseInstallations) > 0 { 624 | for k, v := range m.FirebaseInstallations { 625 | _ = k 626 | _ = v 627 | l = 0 628 | if v != nil { 629 | l = v.SizeVT() 630 | } 631 | l += 1 + sov(uint64(l)) 632 | mapEntrySize := 1 + len(k) + sov(uint64(len(k))) + l 633 | n += mapEntrySize + 1 + sov(uint64(mapEntrySize)) 634 | } 635 | } 636 | l = len(m.MTalkLastPersistentId) 637 | if l > 0 { 638 | n += 1 + l + sov(uint64(l)) 639 | } 640 | l = len(m.FirebaseClientVersion) 641 | if l > 0 { 642 | n += 1 + l + sov(uint64(l)) 643 | } 644 | l = len(m.GmsVersion) 645 | if l > 0 { 646 | n += 1 + l + sov(uint64(l)) 647 | } 648 | l = len(m.MTalkPrivateKey) 649 | if l > 0 { 650 | n += 1 + l + sov(uint64(l)) 651 | } 652 | l = len(m.MTalkPublicKey) 653 | if l > 0 { 654 | n += 1 + l + sov(uint64(l)) 655 | } 656 | l = len(m.MTalkAuthSecret) 657 | if l > 0 { 658 | n += 1 + l + sov(uint64(l)) 659 | } 660 | if m.unknownFields != nil { 661 | n += len(m.unknownFields) 662 | } 663 | return n 664 | } 665 | 666 | func (m *FirebaseAuthentication) UnmarshalVT(dAtA []byte) error { 667 | l := len(dAtA) 668 | iNdEx := 0 669 | for iNdEx < l { 670 | preIndex := iNdEx 671 | var wire uint64 672 | for shift := uint(0); ; shift += 7 { 673 | if shift >= 64 { 674 | return ErrIntOverflow 675 | } 676 | if iNdEx >= l { 677 | return io.ErrUnexpectedEOF 678 | } 679 | b := dAtA[iNdEx] 680 | iNdEx++ 681 | wire |= uint64(b&0x7F) << shift 682 | if b < 0x80 { 683 | break 684 | } 685 | } 686 | fieldNum := int32(wire >> 3) 687 | wireType := int(wire & 0x7) 688 | if wireType == 4 { 689 | return fmt.Errorf("proto: FirebaseAuthentication: wiretype end group for non-group") 690 | } 691 | if fieldNum <= 0 { 692 | return fmt.Errorf("proto: FirebaseAuthentication: illegal tag %d (wire type %d)", fieldNum, wire) 693 | } 694 | switch fieldNum { 695 | case 1: 696 | if wireType != 2 { 697 | return fmt.Errorf("proto: wrong wireType = %d for field AccessToken", wireType) 698 | } 699 | var stringLen uint64 700 | for shift := uint(0); ; shift += 7 { 701 | if shift >= 64 { 702 | return ErrIntOverflow 703 | } 704 | if iNdEx >= l { 705 | return io.ErrUnexpectedEOF 706 | } 707 | b := dAtA[iNdEx] 708 | iNdEx++ 709 | stringLen |= uint64(b&0x7F) << shift 710 | if b < 0x80 { 711 | break 712 | } 713 | } 714 | intStringLen := int(stringLen) 715 | if intStringLen < 0 { 716 | return ErrInvalidLength 717 | } 718 | postIndex := iNdEx + intStringLen 719 | if postIndex < 0 { 720 | return ErrInvalidLength 721 | } 722 | if postIndex > l { 723 | return io.ErrUnexpectedEOF 724 | } 725 | m.AccessToken = string(dAtA[iNdEx:postIndex]) 726 | iNdEx = postIndex 727 | case 2: 728 | if wireType != 2 { 729 | return fmt.Errorf("proto: wrong wireType = %d for field Expires", wireType) 730 | } 731 | var msglen int 732 | for shift := uint(0); ; shift += 7 { 733 | if shift >= 64 { 734 | return ErrIntOverflow 735 | } 736 | if iNdEx >= l { 737 | return io.ErrUnexpectedEOF 738 | } 739 | b := dAtA[iNdEx] 740 | iNdEx++ 741 | msglen |= int(b&0x7F) << shift 742 | if b < 0x80 { 743 | break 744 | } 745 | } 746 | if msglen < 0 { 747 | return ErrInvalidLength 748 | } 749 | postIndex := iNdEx + msglen 750 | if postIndex < 0 { 751 | return ErrInvalidLength 752 | } 753 | if postIndex > l { 754 | return io.ErrUnexpectedEOF 755 | } 756 | if m.Expires == nil { 757 | m.Expires = ×tamppb.Timestamp{} 758 | } 759 | if unmarshal, ok := interface{}(m.Expires).(interface { 760 | UnmarshalVT([]byte) error 761 | }); ok { 762 | if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { 763 | return err 764 | } 765 | } else { 766 | if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Expires); err != nil { 767 | return err 768 | } 769 | } 770 | iNdEx = postIndex 771 | case 3: 772 | if wireType != 2 { 773 | return fmt.Errorf("proto: wrong wireType = %d for field RefreshToken", wireType) 774 | } 775 | var stringLen uint64 776 | for shift := uint(0); ; shift += 7 { 777 | if shift >= 64 { 778 | return ErrIntOverflow 779 | } 780 | if iNdEx >= l { 781 | return io.ErrUnexpectedEOF 782 | } 783 | b := dAtA[iNdEx] 784 | iNdEx++ 785 | stringLen |= uint64(b&0x7F) << shift 786 | if b < 0x80 { 787 | break 788 | } 789 | } 790 | intStringLen := int(stringLen) 791 | if intStringLen < 0 { 792 | return ErrInvalidLength 793 | } 794 | postIndex := iNdEx + intStringLen 795 | if postIndex < 0 { 796 | return ErrInvalidLength 797 | } 798 | if postIndex > l { 799 | return io.ErrUnexpectedEOF 800 | } 801 | m.RefreshToken = string(dAtA[iNdEx:postIndex]) 802 | iNdEx = postIndex 803 | case 4: 804 | if wireType != 2 { 805 | return fmt.Errorf("proto: wrong wireType = %d for field IdToken", wireType) 806 | } 807 | var stringLen uint64 808 | for shift := uint(0); ; shift += 7 { 809 | if shift >= 64 { 810 | return ErrIntOverflow 811 | } 812 | if iNdEx >= l { 813 | return io.ErrUnexpectedEOF 814 | } 815 | b := dAtA[iNdEx] 816 | iNdEx++ 817 | stringLen |= uint64(b&0x7F) << shift 818 | if b < 0x80 { 819 | break 820 | } 821 | } 822 | intStringLen := int(stringLen) 823 | if intStringLen < 0 { 824 | return ErrInvalidLength 825 | } 826 | postIndex := iNdEx + intStringLen 827 | if postIndex < 0 { 828 | return ErrInvalidLength 829 | } 830 | if postIndex > l { 831 | return io.ErrUnexpectedEOF 832 | } 833 | m.IdToken = string(dAtA[iNdEx:postIndex]) 834 | iNdEx = postIndex 835 | default: 836 | iNdEx = preIndex 837 | skippy, err := skip(dAtA[iNdEx:]) 838 | if err != nil { 839 | return err 840 | } 841 | if (skippy < 0) || (iNdEx+skippy) < 0 { 842 | return ErrInvalidLength 843 | } 844 | if (iNdEx + skippy) > l { 845 | return io.ErrUnexpectedEOF 846 | } 847 | m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) 848 | iNdEx += skippy 849 | } 850 | } 851 | 852 | if iNdEx > l { 853 | return io.ErrUnexpectedEOF 854 | } 855 | return nil 856 | } 857 | func (m *FirebaseNotificationData) UnmarshalVT(dAtA []byte) error { 858 | l := len(dAtA) 859 | iNdEx := 0 860 | for iNdEx < l { 861 | preIndex := iNdEx 862 | var wire uint64 863 | for shift := uint(0); ; shift += 7 { 864 | if shift >= 64 { 865 | return ErrIntOverflow 866 | } 867 | if iNdEx >= l { 868 | return io.ErrUnexpectedEOF 869 | } 870 | b := dAtA[iNdEx] 871 | iNdEx++ 872 | wire |= uint64(b&0x7F) << shift 873 | if b < 0x80 { 874 | break 875 | } 876 | } 877 | fieldNum := int32(wire >> 3) 878 | wireType := int(wire & 0x7) 879 | if wireType == 4 { 880 | return fmt.Errorf("proto: FirebaseNotificationData: wiretype end group for non-group") 881 | } 882 | if fieldNum <= 0 { 883 | return fmt.Errorf("proto: FirebaseNotificationData: illegal tag %d (wire type %d)", fieldNum, wire) 884 | } 885 | switch fieldNum { 886 | case 1: 887 | if wireType != 2 { 888 | return fmt.Errorf("proto: wrong wireType = %d for field NotificationToken", wireType) 889 | } 890 | var stringLen uint64 891 | for shift := uint(0); ; shift += 7 { 892 | if shift >= 64 { 893 | return ErrIntOverflow 894 | } 895 | if iNdEx >= l { 896 | return io.ErrUnexpectedEOF 897 | } 898 | b := dAtA[iNdEx] 899 | iNdEx++ 900 | stringLen |= uint64(b&0x7F) << shift 901 | if b < 0x80 { 902 | break 903 | } 904 | } 905 | intStringLen := int(stringLen) 906 | if intStringLen < 0 { 907 | return ErrInvalidLength 908 | } 909 | postIndex := iNdEx + intStringLen 910 | if postIndex < 0 { 911 | return ErrInvalidLength 912 | } 913 | if postIndex > l { 914 | return io.ErrUnexpectedEOF 915 | } 916 | m.NotificationToken = string(dAtA[iNdEx:postIndex]) 917 | iNdEx = postIndex 918 | case 2: 919 | if wireType != 2 { 920 | return fmt.Errorf("proto: wrong wireType = %d for field PrivateKey", wireType) 921 | } 922 | var byteLen int 923 | for shift := uint(0); ; shift += 7 { 924 | if shift >= 64 { 925 | return ErrIntOverflow 926 | } 927 | if iNdEx >= l { 928 | return io.ErrUnexpectedEOF 929 | } 930 | b := dAtA[iNdEx] 931 | iNdEx++ 932 | byteLen |= int(b&0x7F) << shift 933 | if b < 0x80 { 934 | break 935 | } 936 | } 937 | if byteLen < 0 { 938 | return ErrInvalidLength 939 | } 940 | postIndex := iNdEx + byteLen 941 | if postIndex < 0 { 942 | return ErrInvalidLength 943 | } 944 | if postIndex > l { 945 | return io.ErrUnexpectedEOF 946 | } 947 | m.PrivateKey = append(m.PrivateKey[:0], dAtA[iNdEx:postIndex]...) 948 | if m.PrivateKey == nil { 949 | m.PrivateKey = []byte{} 950 | } 951 | iNdEx = postIndex 952 | case 3: 953 | if wireType != 2 { 954 | return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) 955 | } 956 | var byteLen int 957 | for shift := uint(0); ; shift += 7 { 958 | if shift >= 64 { 959 | return ErrIntOverflow 960 | } 961 | if iNdEx >= l { 962 | return io.ErrUnexpectedEOF 963 | } 964 | b := dAtA[iNdEx] 965 | iNdEx++ 966 | byteLen |= int(b&0x7F) << shift 967 | if b < 0x80 { 968 | break 969 | } 970 | } 971 | if byteLen < 0 { 972 | return ErrInvalidLength 973 | } 974 | postIndex := iNdEx + byteLen 975 | if postIndex < 0 { 976 | return ErrInvalidLength 977 | } 978 | if postIndex > l { 979 | return io.ErrUnexpectedEOF 980 | } 981 | m.PublicKey = append(m.PublicKey[:0], dAtA[iNdEx:postIndex]...) 982 | if m.PublicKey == nil { 983 | m.PublicKey = []byte{} 984 | } 985 | iNdEx = postIndex 986 | case 4: 987 | if wireType != 2 { 988 | return fmt.Errorf("proto: wrong wireType = %d for field Secret", wireType) 989 | } 990 | var byteLen int 991 | for shift := uint(0); ; shift += 7 { 992 | if shift >= 64 { 993 | return ErrIntOverflow 994 | } 995 | if iNdEx >= l { 996 | return io.ErrUnexpectedEOF 997 | } 998 | b := dAtA[iNdEx] 999 | iNdEx++ 1000 | byteLen |= int(b&0x7F) << shift 1001 | if b < 0x80 { 1002 | break 1003 | } 1004 | } 1005 | if byteLen < 0 { 1006 | return ErrInvalidLength 1007 | } 1008 | postIndex := iNdEx + byteLen 1009 | if postIndex < 0 { 1010 | return ErrInvalidLength 1011 | } 1012 | if postIndex > l { 1013 | return io.ErrUnexpectedEOF 1014 | } 1015 | m.Secret = append(m.Secret[:0], dAtA[iNdEx:postIndex]...) 1016 | if m.Secret == nil { 1017 | m.Secret = []byte{} 1018 | } 1019 | iNdEx = postIndex 1020 | default: 1021 | iNdEx = preIndex 1022 | skippy, err := skip(dAtA[iNdEx:]) 1023 | if err != nil { 1024 | return err 1025 | } 1026 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1027 | return ErrInvalidLength 1028 | } 1029 | if (iNdEx + skippy) > l { 1030 | return io.ErrUnexpectedEOF 1031 | } 1032 | m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) 1033 | iNdEx += skippy 1034 | } 1035 | } 1036 | 1037 | if iNdEx > l { 1038 | return io.ErrUnexpectedEOF 1039 | } 1040 | return nil 1041 | } 1042 | func (m *FirebaseInstallationData) UnmarshalVT(dAtA []byte) error { 1043 | l := len(dAtA) 1044 | iNdEx := 0 1045 | for iNdEx < l { 1046 | preIndex := iNdEx 1047 | var wire uint64 1048 | for shift := uint(0); ; shift += 7 { 1049 | if shift >= 64 { 1050 | return ErrIntOverflow 1051 | } 1052 | if iNdEx >= l { 1053 | return io.ErrUnexpectedEOF 1054 | } 1055 | b := dAtA[iNdEx] 1056 | iNdEx++ 1057 | wire |= uint64(b&0x7F) << shift 1058 | if b < 0x80 { 1059 | break 1060 | } 1061 | } 1062 | fieldNum := int32(wire >> 3) 1063 | wireType := int(wire & 0x7) 1064 | if wireType == 4 { 1065 | return fmt.Errorf("proto: FirebaseInstallationData: wiretype end group for non-group") 1066 | } 1067 | if fieldNum <= 0 { 1068 | return fmt.Errorf("proto: FirebaseInstallationData: illegal tag %d (wire type %d)", fieldNum, wire) 1069 | } 1070 | switch fieldNum { 1071 | case 1: 1072 | if wireType != 2 { 1073 | return fmt.Errorf("proto: wrong wireType = %d for field FirebaseInstallationID", wireType) 1074 | } 1075 | var stringLen uint64 1076 | for shift := uint(0); ; shift += 7 { 1077 | if shift >= 64 { 1078 | return ErrIntOverflow 1079 | } 1080 | if iNdEx >= l { 1081 | return io.ErrUnexpectedEOF 1082 | } 1083 | b := dAtA[iNdEx] 1084 | iNdEx++ 1085 | stringLen |= uint64(b&0x7F) << shift 1086 | if b < 0x80 { 1087 | break 1088 | } 1089 | } 1090 | intStringLen := int(stringLen) 1091 | if intStringLen < 0 { 1092 | return ErrInvalidLength 1093 | } 1094 | postIndex := iNdEx + intStringLen 1095 | if postIndex < 0 { 1096 | return ErrInvalidLength 1097 | } 1098 | if postIndex > l { 1099 | return io.ErrUnexpectedEOF 1100 | } 1101 | m.FirebaseInstallationID = string(dAtA[iNdEx:postIndex]) 1102 | iNdEx = postIndex 1103 | case 2: 1104 | if wireType != 2 { 1105 | return fmt.Errorf("proto: wrong wireType = %d for field NotificationData", wireType) 1106 | } 1107 | var msglen int 1108 | for shift := uint(0); ; shift += 7 { 1109 | if shift >= 64 { 1110 | return ErrIntOverflow 1111 | } 1112 | if iNdEx >= l { 1113 | return io.ErrUnexpectedEOF 1114 | } 1115 | b := dAtA[iNdEx] 1116 | iNdEx++ 1117 | msglen |= int(b&0x7F) << shift 1118 | if b < 0x80 { 1119 | break 1120 | } 1121 | } 1122 | if msglen < 0 { 1123 | return ErrInvalidLength 1124 | } 1125 | postIndex := iNdEx + msglen 1126 | if postIndex < 0 { 1127 | return ErrInvalidLength 1128 | } 1129 | if postIndex > l { 1130 | return io.ErrUnexpectedEOF 1131 | } 1132 | if m.NotificationData == nil { 1133 | m.NotificationData = &FirebaseNotificationData{} 1134 | } 1135 | if err := m.NotificationData.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { 1136 | return err 1137 | } 1138 | iNdEx = postIndex 1139 | case 3: 1140 | if wireType != 2 { 1141 | return fmt.Errorf("proto: wrong wireType = %d for field InstallationAuthentication", wireType) 1142 | } 1143 | var msglen int 1144 | for shift := uint(0); ; shift += 7 { 1145 | if shift >= 64 { 1146 | return ErrIntOverflow 1147 | } 1148 | if iNdEx >= l { 1149 | return io.ErrUnexpectedEOF 1150 | } 1151 | b := dAtA[iNdEx] 1152 | iNdEx++ 1153 | msglen |= int(b&0x7F) << shift 1154 | if b < 0x80 { 1155 | break 1156 | } 1157 | } 1158 | if msglen < 0 { 1159 | return ErrInvalidLength 1160 | } 1161 | postIndex := iNdEx + msglen 1162 | if postIndex < 0 { 1163 | return ErrInvalidLength 1164 | } 1165 | if postIndex > l { 1166 | return io.ErrUnexpectedEOF 1167 | } 1168 | if m.InstallationAuthentication == nil { 1169 | m.InstallationAuthentication = &FirebaseAuthentication{} 1170 | } 1171 | if err := m.InstallationAuthentication.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { 1172 | return err 1173 | } 1174 | iNdEx = postIndex 1175 | default: 1176 | iNdEx = preIndex 1177 | skippy, err := skip(dAtA[iNdEx:]) 1178 | if err != nil { 1179 | return err 1180 | } 1181 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1182 | return ErrInvalidLength 1183 | } 1184 | if (iNdEx + skippy) > l { 1185 | return io.ErrUnexpectedEOF 1186 | } 1187 | m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) 1188 | iNdEx += skippy 1189 | } 1190 | } 1191 | 1192 | if iNdEx > l { 1193 | return io.ErrUnexpectedEOF 1194 | } 1195 | return nil 1196 | } 1197 | func (m *FirebaseAppData) UnmarshalVT(dAtA []byte) error { 1198 | l := len(dAtA) 1199 | iNdEx := 0 1200 | for iNdEx < l { 1201 | preIndex := iNdEx 1202 | var wire uint64 1203 | for shift := uint(0); ; shift += 7 { 1204 | if shift >= 64 { 1205 | return ErrIntOverflow 1206 | } 1207 | if iNdEx >= l { 1208 | return io.ErrUnexpectedEOF 1209 | } 1210 | b := dAtA[iNdEx] 1211 | iNdEx++ 1212 | wire |= uint64(b&0x7F) << shift 1213 | if b < 0x80 { 1214 | break 1215 | } 1216 | } 1217 | fieldNum := int32(wire >> 3) 1218 | wireType := int(wire & 0x7) 1219 | if wireType == 4 { 1220 | return fmt.Errorf("proto: FirebaseAppData: wiretype end group for non-group") 1221 | } 1222 | if fieldNum <= 0 { 1223 | return fmt.Errorf("proto: FirebaseAppData: illegal tag %d (wire type %d)", fieldNum, wire) 1224 | } 1225 | switch fieldNum { 1226 | case 1: 1227 | if wireType != 2 { 1228 | return fmt.Errorf("proto: wrong wireType = %d for field PackageID", wireType) 1229 | } 1230 | var stringLen uint64 1231 | for shift := uint(0); ; shift += 7 { 1232 | if shift >= 64 { 1233 | return ErrIntOverflow 1234 | } 1235 | if iNdEx >= l { 1236 | return io.ErrUnexpectedEOF 1237 | } 1238 | b := dAtA[iNdEx] 1239 | iNdEx++ 1240 | stringLen |= uint64(b&0x7F) << shift 1241 | if b < 0x80 { 1242 | break 1243 | } 1244 | } 1245 | intStringLen := int(stringLen) 1246 | if intStringLen < 0 { 1247 | return ErrInvalidLength 1248 | } 1249 | postIndex := iNdEx + intStringLen 1250 | if postIndex < 0 { 1251 | return ErrInvalidLength 1252 | } 1253 | if postIndex > l { 1254 | return io.ErrUnexpectedEOF 1255 | } 1256 | m.PackageID = string(dAtA[iNdEx:postIndex]) 1257 | iNdEx = postIndex 1258 | case 2: 1259 | if wireType != 2 { 1260 | return fmt.Errorf("proto: wrong wireType = %d for field PackageCertificate", wireType) 1261 | } 1262 | var stringLen uint64 1263 | for shift := uint(0); ; shift += 7 { 1264 | if shift >= 64 { 1265 | return ErrIntOverflow 1266 | } 1267 | if iNdEx >= l { 1268 | return io.ErrUnexpectedEOF 1269 | } 1270 | b := dAtA[iNdEx] 1271 | iNdEx++ 1272 | stringLen |= uint64(b&0x7F) << shift 1273 | if b < 0x80 { 1274 | break 1275 | } 1276 | } 1277 | intStringLen := int(stringLen) 1278 | if intStringLen < 0 { 1279 | return ErrInvalidLength 1280 | } 1281 | postIndex := iNdEx + intStringLen 1282 | if postIndex < 0 { 1283 | return ErrInvalidLength 1284 | } 1285 | if postIndex > l { 1286 | return io.ErrUnexpectedEOF 1287 | } 1288 | m.PackageCertificate = string(dAtA[iNdEx:postIndex]) 1289 | iNdEx = postIndex 1290 | case 3: 1291 | if wireType != 2 { 1292 | return fmt.Errorf("proto: wrong wireType = %d for field GoogleAPIKey", wireType) 1293 | } 1294 | var stringLen uint64 1295 | for shift := uint(0); ; shift += 7 { 1296 | if shift >= 64 { 1297 | return ErrIntOverflow 1298 | } 1299 | if iNdEx >= l { 1300 | return io.ErrUnexpectedEOF 1301 | } 1302 | b := dAtA[iNdEx] 1303 | iNdEx++ 1304 | stringLen |= uint64(b&0x7F) << shift 1305 | if b < 0x80 { 1306 | break 1307 | } 1308 | } 1309 | intStringLen := int(stringLen) 1310 | if intStringLen < 0 { 1311 | return ErrInvalidLength 1312 | } 1313 | postIndex := iNdEx + intStringLen 1314 | if postIndex < 0 { 1315 | return ErrInvalidLength 1316 | } 1317 | if postIndex > l { 1318 | return io.ErrUnexpectedEOF 1319 | } 1320 | m.GoogleAPIKey = string(dAtA[iNdEx:postIndex]) 1321 | iNdEx = postIndex 1322 | case 4: 1323 | if wireType != 2 { 1324 | return fmt.Errorf("proto: wrong wireType = %d for field FirebaseProjectID", wireType) 1325 | } 1326 | var stringLen uint64 1327 | for shift := uint(0); ; shift += 7 { 1328 | if shift >= 64 { 1329 | return ErrIntOverflow 1330 | } 1331 | if iNdEx >= l { 1332 | return io.ErrUnexpectedEOF 1333 | } 1334 | b := dAtA[iNdEx] 1335 | iNdEx++ 1336 | stringLen |= uint64(b&0x7F) << shift 1337 | if b < 0x80 { 1338 | break 1339 | } 1340 | } 1341 | intStringLen := int(stringLen) 1342 | if intStringLen < 0 { 1343 | return ErrInvalidLength 1344 | } 1345 | postIndex := iNdEx + intStringLen 1346 | if postIndex < 0 { 1347 | return ErrInvalidLength 1348 | } 1349 | if postIndex > l { 1350 | return io.ErrUnexpectedEOF 1351 | } 1352 | m.FirebaseProjectID = string(dAtA[iNdEx:postIndex]) 1353 | iNdEx = postIndex 1354 | case 5: 1355 | if wireType != 2 { 1356 | return fmt.Errorf("proto: wrong wireType = %d for field NotificationSenderID", wireType) 1357 | } 1358 | var stringLen uint64 1359 | for shift := uint(0); ; shift += 7 { 1360 | if shift >= 64 { 1361 | return ErrIntOverflow 1362 | } 1363 | if iNdEx >= l { 1364 | return io.ErrUnexpectedEOF 1365 | } 1366 | b := dAtA[iNdEx] 1367 | iNdEx++ 1368 | stringLen |= uint64(b&0x7F) << shift 1369 | if b < 0x80 { 1370 | break 1371 | } 1372 | } 1373 | intStringLen := int(stringLen) 1374 | if intStringLen < 0 { 1375 | return ErrInvalidLength 1376 | } 1377 | postIndex := iNdEx + intStringLen 1378 | if postIndex < 0 { 1379 | return ErrInvalidLength 1380 | } 1381 | if postIndex > l { 1382 | return io.ErrUnexpectedEOF 1383 | } 1384 | m.NotificationSenderID = string(dAtA[iNdEx:postIndex]) 1385 | iNdEx = postIndex 1386 | case 6: 1387 | if wireType != 2 { 1388 | return fmt.Errorf("proto: wrong wireType = %d for field GMPAppID", wireType) 1389 | } 1390 | var stringLen uint64 1391 | for shift := uint(0); ; shift += 7 { 1392 | if shift >= 64 { 1393 | return ErrIntOverflow 1394 | } 1395 | if iNdEx >= l { 1396 | return io.ErrUnexpectedEOF 1397 | } 1398 | b := dAtA[iNdEx] 1399 | iNdEx++ 1400 | stringLen |= uint64(b&0x7F) << shift 1401 | if b < 0x80 { 1402 | break 1403 | } 1404 | } 1405 | intStringLen := int(stringLen) 1406 | if intStringLen < 0 { 1407 | return ErrInvalidLength 1408 | } 1409 | postIndex := iNdEx + intStringLen 1410 | if postIndex < 0 { 1411 | return ErrInvalidLength 1412 | } 1413 | if postIndex > l { 1414 | return io.ErrUnexpectedEOF 1415 | } 1416 | m.GMPAppID = string(dAtA[iNdEx:postIndex]) 1417 | iNdEx = postIndex 1418 | case 7: 1419 | if wireType != 2 { 1420 | return fmt.Errorf("proto: wrong wireType = %d for field AppVersion", wireType) 1421 | } 1422 | var stringLen uint64 1423 | for shift := uint(0); ; shift += 7 { 1424 | if shift >= 64 { 1425 | return ErrIntOverflow 1426 | } 1427 | if iNdEx >= l { 1428 | return io.ErrUnexpectedEOF 1429 | } 1430 | b := dAtA[iNdEx] 1431 | iNdEx++ 1432 | stringLen |= uint64(b&0x7F) << shift 1433 | if b < 0x80 { 1434 | break 1435 | } 1436 | } 1437 | intStringLen := int(stringLen) 1438 | if intStringLen < 0 { 1439 | return ErrInvalidLength 1440 | } 1441 | postIndex := iNdEx + intStringLen 1442 | if postIndex < 0 { 1443 | return ErrInvalidLength 1444 | } 1445 | if postIndex > l { 1446 | return io.ErrUnexpectedEOF 1447 | } 1448 | m.AppVersion = string(dAtA[iNdEx:postIndex]) 1449 | iNdEx = postIndex 1450 | case 8: 1451 | if wireType != 2 { 1452 | return fmt.Errorf("proto: wrong wireType = %d for field AppVersionWithBuild", wireType) 1453 | } 1454 | var stringLen uint64 1455 | for shift := uint(0); ; shift += 7 { 1456 | if shift >= 64 { 1457 | return ErrIntOverflow 1458 | } 1459 | if iNdEx >= l { 1460 | return io.ErrUnexpectedEOF 1461 | } 1462 | b := dAtA[iNdEx] 1463 | iNdEx++ 1464 | stringLen |= uint64(b&0x7F) << shift 1465 | if b < 0x80 { 1466 | break 1467 | } 1468 | } 1469 | intStringLen := int(stringLen) 1470 | if intStringLen < 0 { 1471 | return ErrInvalidLength 1472 | } 1473 | postIndex := iNdEx + intStringLen 1474 | if postIndex < 0 { 1475 | return ErrInvalidLength 1476 | } 1477 | if postIndex > l { 1478 | return io.ErrUnexpectedEOF 1479 | } 1480 | m.AppVersionWithBuild = string(dAtA[iNdEx:postIndex]) 1481 | iNdEx = postIndex 1482 | case 9: 1483 | if wireType != 2 { 1484 | return fmt.Errorf("proto: wrong wireType = %d for field AuthVersion", wireType) 1485 | } 1486 | var stringLen uint64 1487 | for shift := uint(0); ; shift += 7 { 1488 | if shift >= 64 { 1489 | return ErrIntOverflow 1490 | } 1491 | if iNdEx >= l { 1492 | return io.ErrUnexpectedEOF 1493 | } 1494 | b := dAtA[iNdEx] 1495 | iNdEx++ 1496 | stringLen |= uint64(b&0x7F) << shift 1497 | if b < 0x80 { 1498 | break 1499 | } 1500 | } 1501 | intStringLen := int(stringLen) 1502 | if intStringLen < 0 { 1503 | return ErrInvalidLength 1504 | } 1505 | postIndex := iNdEx + intStringLen 1506 | if postIndex < 0 { 1507 | return ErrInvalidLength 1508 | } 1509 | if postIndex > l { 1510 | return io.ErrUnexpectedEOF 1511 | } 1512 | m.AuthVersion = string(dAtA[iNdEx:postIndex]) 1513 | iNdEx = postIndex 1514 | case 10: 1515 | if wireType != 2 { 1516 | return fmt.Errorf("proto: wrong wireType = %d for field SdkVersion", wireType) 1517 | } 1518 | var stringLen uint64 1519 | for shift := uint(0); ; shift += 7 { 1520 | if shift >= 64 { 1521 | return ErrIntOverflow 1522 | } 1523 | if iNdEx >= l { 1524 | return io.ErrUnexpectedEOF 1525 | } 1526 | b := dAtA[iNdEx] 1527 | iNdEx++ 1528 | stringLen |= uint64(b&0x7F) << shift 1529 | if b < 0x80 { 1530 | break 1531 | } 1532 | } 1533 | intStringLen := int(stringLen) 1534 | if intStringLen < 0 { 1535 | return ErrInvalidLength 1536 | } 1537 | postIndex := iNdEx + intStringLen 1538 | if postIndex < 0 { 1539 | return ErrInvalidLength 1540 | } 1541 | if postIndex > l { 1542 | return io.ErrUnexpectedEOF 1543 | } 1544 | m.SdkVersion = string(dAtA[iNdEx:postIndex]) 1545 | iNdEx = postIndex 1546 | case 11: 1547 | if wireType != 2 { 1548 | return fmt.Errorf("proto: wrong wireType = %d for field AppNameHash", wireType) 1549 | } 1550 | var stringLen uint64 1551 | for shift := uint(0); ; shift += 7 { 1552 | if shift >= 64 { 1553 | return ErrIntOverflow 1554 | } 1555 | if iNdEx >= l { 1556 | return io.ErrUnexpectedEOF 1557 | } 1558 | b := dAtA[iNdEx] 1559 | iNdEx++ 1560 | stringLen |= uint64(b&0x7F) << shift 1561 | if b < 0x80 { 1562 | break 1563 | } 1564 | } 1565 | intStringLen := int(stringLen) 1566 | if intStringLen < 0 { 1567 | return ErrInvalidLength 1568 | } 1569 | postIndex := iNdEx + intStringLen 1570 | if postIndex < 0 { 1571 | return ErrInvalidLength 1572 | } 1573 | if postIndex > l { 1574 | return io.ErrUnexpectedEOF 1575 | } 1576 | m.AppNameHash = string(dAtA[iNdEx:postIndex]) 1577 | iNdEx = postIndex 1578 | default: 1579 | iNdEx = preIndex 1580 | skippy, err := skip(dAtA[iNdEx:]) 1581 | if err != nil { 1582 | return err 1583 | } 1584 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1585 | return ErrInvalidLength 1586 | } 1587 | if (iNdEx + skippy) > l { 1588 | return io.ErrUnexpectedEOF 1589 | } 1590 | m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) 1591 | iNdEx += skippy 1592 | } 1593 | } 1594 | 1595 | if iNdEx > l { 1596 | return io.ErrUnexpectedEOF 1597 | } 1598 | return nil 1599 | } 1600 | func (m *FirebaseDevice) UnmarshalVT(dAtA []byte) error { 1601 | l := len(dAtA) 1602 | iNdEx := 0 1603 | for iNdEx < l { 1604 | preIndex := iNdEx 1605 | var wire uint64 1606 | for shift := uint(0); ; shift += 7 { 1607 | if shift >= 64 { 1608 | return ErrIntOverflow 1609 | } 1610 | if iNdEx >= l { 1611 | return io.ErrUnexpectedEOF 1612 | } 1613 | b := dAtA[iNdEx] 1614 | iNdEx++ 1615 | wire |= uint64(b&0x7F) << shift 1616 | if b < 0x80 { 1617 | break 1618 | } 1619 | } 1620 | fieldNum := int32(wire >> 3) 1621 | wireType := int(wire & 0x7) 1622 | if wireType == 4 { 1623 | return fmt.Errorf("proto: FirebaseDevice: wiretype end group for non-group") 1624 | } 1625 | if fieldNum <= 0 { 1626 | return fmt.Errorf("proto: FirebaseDevice: illegal tag %d (wire type %d)", fieldNum, wire) 1627 | } 1628 | switch fieldNum { 1629 | case 1: 1630 | if wireType != 2 { 1631 | return fmt.Errorf("proto: wrong wireType = %d for field Device", wireType) 1632 | } 1633 | var msglen int 1634 | for shift := uint(0); ; shift += 7 { 1635 | if shift >= 64 { 1636 | return ErrIntOverflow 1637 | } 1638 | if iNdEx >= l { 1639 | return io.ErrUnexpectedEOF 1640 | } 1641 | b := dAtA[iNdEx] 1642 | iNdEx++ 1643 | msglen |= int(b&0x7F) << shift 1644 | if b < 0x80 { 1645 | break 1646 | } 1647 | } 1648 | if msglen < 0 { 1649 | return ErrInvalidLength 1650 | } 1651 | postIndex := iNdEx + msglen 1652 | if postIndex < 0 { 1653 | return ErrInvalidLength 1654 | } 1655 | if postIndex > l { 1656 | return io.ErrUnexpectedEOF 1657 | } 1658 | if m.Device == nil { 1659 | m.Device = &go_android_utils.Device{} 1660 | } 1661 | if unmarshal, ok := interface{}(m.Device).(interface { 1662 | UnmarshalVT([]byte) error 1663 | }); ok { 1664 | if err := unmarshal.UnmarshalVT(dAtA[iNdEx:postIndex]); err != nil { 1665 | return err 1666 | } 1667 | } else { 1668 | if err := proto.Unmarshal(dAtA[iNdEx:postIndex], m.Device); err != nil { 1669 | return err 1670 | } 1671 | } 1672 | iNdEx = postIndex 1673 | case 2: 1674 | if wireType != 0 { 1675 | return fmt.Errorf("proto: wrong wireType = %d for field CheckinAndroidID", wireType) 1676 | } 1677 | m.CheckinAndroidID = 0 1678 | for shift := uint(0); ; shift += 7 { 1679 | if shift >= 64 { 1680 | return ErrIntOverflow 1681 | } 1682 | if iNdEx >= l { 1683 | return io.ErrUnexpectedEOF 1684 | } 1685 | b := dAtA[iNdEx] 1686 | iNdEx++ 1687 | m.CheckinAndroidID |= int64(b&0x7F) << shift 1688 | if b < 0x80 { 1689 | break 1690 | } 1691 | } 1692 | case 3: 1693 | if wireType != 0 { 1694 | return fmt.Errorf("proto: wrong wireType = %d for field CheckinSecurityToken", wireType) 1695 | } 1696 | m.CheckinSecurityToken = 0 1697 | for shift := uint(0); ; shift += 7 { 1698 | if shift >= 64 { 1699 | return ErrIntOverflow 1700 | } 1701 | if iNdEx >= l { 1702 | return io.ErrUnexpectedEOF 1703 | } 1704 | b := dAtA[iNdEx] 1705 | iNdEx++ 1706 | m.CheckinSecurityToken |= uint64(b&0x7F) << shift 1707 | if b < 0x80 { 1708 | break 1709 | } 1710 | } 1711 | case 4: 1712 | if wireType != 2 { 1713 | return fmt.Errorf("proto: wrong wireType = %d for field FirebaseInstallations", wireType) 1714 | } 1715 | var msglen int 1716 | for shift := uint(0); ; shift += 7 { 1717 | if shift >= 64 { 1718 | return ErrIntOverflow 1719 | } 1720 | if iNdEx >= l { 1721 | return io.ErrUnexpectedEOF 1722 | } 1723 | b := dAtA[iNdEx] 1724 | iNdEx++ 1725 | msglen |= int(b&0x7F) << shift 1726 | if b < 0x80 { 1727 | break 1728 | } 1729 | } 1730 | if msglen < 0 { 1731 | return ErrInvalidLength 1732 | } 1733 | postIndex := iNdEx + msglen 1734 | if postIndex < 0 { 1735 | return ErrInvalidLength 1736 | } 1737 | if postIndex > l { 1738 | return io.ErrUnexpectedEOF 1739 | } 1740 | if m.FirebaseInstallations == nil { 1741 | m.FirebaseInstallations = make(map[string]*FirebaseInstallationData) 1742 | } 1743 | var mapkey string 1744 | var mapvalue *FirebaseInstallationData 1745 | for iNdEx < postIndex { 1746 | entryPreIndex := iNdEx 1747 | var wire uint64 1748 | for shift := uint(0); ; shift += 7 { 1749 | if shift >= 64 { 1750 | return ErrIntOverflow 1751 | } 1752 | if iNdEx >= l { 1753 | return io.ErrUnexpectedEOF 1754 | } 1755 | b := dAtA[iNdEx] 1756 | iNdEx++ 1757 | wire |= uint64(b&0x7F) << shift 1758 | if b < 0x80 { 1759 | break 1760 | } 1761 | } 1762 | fieldNum := int32(wire >> 3) 1763 | if fieldNum == 1 { 1764 | var stringLenmapkey uint64 1765 | for shift := uint(0); ; shift += 7 { 1766 | if shift >= 64 { 1767 | return ErrIntOverflow 1768 | } 1769 | if iNdEx >= l { 1770 | return io.ErrUnexpectedEOF 1771 | } 1772 | b := dAtA[iNdEx] 1773 | iNdEx++ 1774 | stringLenmapkey |= uint64(b&0x7F) << shift 1775 | if b < 0x80 { 1776 | break 1777 | } 1778 | } 1779 | intStringLenmapkey := int(stringLenmapkey) 1780 | if intStringLenmapkey < 0 { 1781 | return ErrInvalidLength 1782 | } 1783 | postStringIndexmapkey := iNdEx + intStringLenmapkey 1784 | if postStringIndexmapkey < 0 { 1785 | return ErrInvalidLength 1786 | } 1787 | if postStringIndexmapkey > l { 1788 | return io.ErrUnexpectedEOF 1789 | } 1790 | mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) 1791 | iNdEx = postStringIndexmapkey 1792 | } else if fieldNum == 2 { 1793 | var mapmsglen int 1794 | for shift := uint(0); ; shift += 7 { 1795 | if shift >= 64 { 1796 | return ErrIntOverflow 1797 | } 1798 | if iNdEx >= l { 1799 | return io.ErrUnexpectedEOF 1800 | } 1801 | b := dAtA[iNdEx] 1802 | iNdEx++ 1803 | mapmsglen |= int(b&0x7F) << shift 1804 | if b < 0x80 { 1805 | break 1806 | } 1807 | } 1808 | if mapmsglen < 0 { 1809 | return ErrInvalidLength 1810 | } 1811 | postmsgIndex := iNdEx + mapmsglen 1812 | if postmsgIndex < 0 { 1813 | return ErrInvalidLength 1814 | } 1815 | if postmsgIndex > l { 1816 | return io.ErrUnexpectedEOF 1817 | } 1818 | mapvalue = &FirebaseInstallationData{} 1819 | if err := mapvalue.UnmarshalVT(dAtA[iNdEx:postmsgIndex]); err != nil { 1820 | return err 1821 | } 1822 | iNdEx = postmsgIndex 1823 | } else { 1824 | iNdEx = entryPreIndex 1825 | skippy, err := skip(dAtA[iNdEx:]) 1826 | if err != nil { 1827 | return err 1828 | } 1829 | if (skippy < 0) || (iNdEx+skippy) < 0 { 1830 | return ErrInvalidLength 1831 | } 1832 | if (iNdEx + skippy) > postIndex { 1833 | return io.ErrUnexpectedEOF 1834 | } 1835 | iNdEx += skippy 1836 | } 1837 | } 1838 | m.FirebaseInstallations[mapkey] = mapvalue 1839 | iNdEx = postIndex 1840 | case 5: 1841 | if wireType != 2 { 1842 | return fmt.Errorf("proto: wrong wireType = %d for field MTalkLastPersistentId", wireType) 1843 | } 1844 | var stringLen uint64 1845 | for shift := uint(0); ; shift += 7 { 1846 | if shift >= 64 { 1847 | return ErrIntOverflow 1848 | } 1849 | if iNdEx >= l { 1850 | return io.ErrUnexpectedEOF 1851 | } 1852 | b := dAtA[iNdEx] 1853 | iNdEx++ 1854 | stringLen |= uint64(b&0x7F) << shift 1855 | if b < 0x80 { 1856 | break 1857 | } 1858 | } 1859 | intStringLen := int(stringLen) 1860 | if intStringLen < 0 { 1861 | return ErrInvalidLength 1862 | } 1863 | postIndex := iNdEx + intStringLen 1864 | if postIndex < 0 { 1865 | return ErrInvalidLength 1866 | } 1867 | if postIndex > l { 1868 | return io.ErrUnexpectedEOF 1869 | } 1870 | m.MTalkLastPersistentId = string(dAtA[iNdEx:postIndex]) 1871 | iNdEx = postIndex 1872 | case 6: 1873 | if wireType != 2 { 1874 | return fmt.Errorf("proto: wrong wireType = %d for field FirebaseClientVersion", wireType) 1875 | } 1876 | var stringLen uint64 1877 | for shift := uint(0); ; shift += 7 { 1878 | if shift >= 64 { 1879 | return ErrIntOverflow 1880 | } 1881 | if iNdEx >= l { 1882 | return io.ErrUnexpectedEOF 1883 | } 1884 | b := dAtA[iNdEx] 1885 | iNdEx++ 1886 | stringLen |= uint64(b&0x7F) << shift 1887 | if b < 0x80 { 1888 | break 1889 | } 1890 | } 1891 | intStringLen := int(stringLen) 1892 | if intStringLen < 0 { 1893 | return ErrInvalidLength 1894 | } 1895 | postIndex := iNdEx + intStringLen 1896 | if postIndex < 0 { 1897 | return ErrInvalidLength 1898 | } 1899 | if postIndex > l { 1900 | return io.ErrUnexpectedEOF 1901 | } 1902 | m.FirebaseClientVersion = string(dAtA[iNdEx:postIndex]) 1903 | iNdEx = postIndex 1904 | case 7: 1905 | if wireType != 2 { 1906 | return fmt.Errorf("proto: wrong wireType = %d for field GmsVersion", wireType) 1907 | } 1908 | var stringLen uint64 1909 | for shift := uint(0); ; shift += 7 { 1910 | if shift >= 64 { 1911 | return ErrIntOverflow 1912 | } 1913 | if iNdEx >= l { 1914 | return io.ErrUnexpectedEOF 1915 | } 1916 | b := dAtA[iNdEx] 1917 | iNdEx++ 1918 | stringLen |= uint64(b&0x7F) << shift 1919 | if b < 0x80 { 1920 | break 1921 | } 1922 | } 1923 | intStringLen := int(stringLen) 1924 | if intStringLen < 0 { 1925 | return ErrInvalidLength 1926 | } 1927 | postIndex := iNdEx + intStringLen 1928 | if postIndex < 0 { 1929 | return ErrInvalidLength 1930 | } 1931 | if postIndex > l { 1932 | return io.ErrUnexpectedEOF 1933 | } 1934 | m.GmsVersion = string(dAtA[iNdEx:postIndex]) 1935 | iNdEx = postIndex 1936 | case 8: 1937 | if wireType != 2 { 1938 | return fmt.Errorf("proto: wrong wireType = %d for field MTalkPrivateKey", wireType) 1939 | } 1940 | var stringLen uint64 1941 | for shift := uint(0); ; shift += 7 { 1942 | if shift >= 64 { 1943 | return ErrIntOverflow 1944 | } 1945 | if iNdEx >= l { 1946 | return io.ErrUnexpectedEOF 1947 | } 1948 | b := dAtA[iNdEx] 1949 | iNdEx++ 1950 | stringLen |= uint64(b&0x7F) << shift 1951 | if b < 0x80 { 1952 | break 1953 | } 1954 | } 1955 | intStringLen := int(stringLen) 1956 | if intStringLen < 0 { 1957 | return ErrInvalidLength 1958 | } 1959 | postIndex := iNdEx + intStringLen 1960 | if postIndex < 0 { 1961 | return ErrInvalidLength 1962 | } 1963 | if postIndex > l { 1964 | return io.ErrUnexpectedEOF 1965 | } 1966 | m.MTalkPrivateKey = string(dAtA[iNdEx:postIndex]) 1967 | iNdEx = postIndex 1968 | case 9: 1969 | if wireType != 2 { 1970 | return fmt.Errorf("proto: wrong wireType = %d for field MTalkPublicKey", wireType) 1971 | } 1972 | var stringLen uint64 1973 | for shift := uint(0); ; shift += 7 { 1974 | if shift >= 64 { 1975 | return ErrIntOverflow 1976 | } 1977 | if iNdEx >= l { 1978 | return io.ErrUnexpectedEOF 1979 | } 1980 | b := dAtA[iNdEx] 1981 | iNdEx++ 1982 | stringLen |= uint64(b&0x7F) << shift 1983 | if b < 0x80 { 1984 | break 1985 | } 1986 | } 1987 | intStringLen := int(stringLen) 1988 | if intStringLen < 0 { 1989 | return ErrInvalidLength 1990 | } 1991 | postIndex := iNdEx + intStringLen 1992 | if postIndex < 0 { 1993 | return ErrInvalidLength 1994 | } 1995 | if postIndex > l { 1996 | return io.ErrUnexpectedEOF 1997 | } 1998 | m.MTalkPublicKey = string(dAtA[iNdEx:postIndex]) 1999 | iNdEx = postIndex 2000 | case 10: 2001 | if wireType != 2 { 2002 | return fmt.Errorf("proto: wrong wireType = %d for field MTalkAuthSecret", wireType) 2003 | } 2004 | var stringLen uint64 2005 | for shift := uint(0); ; shift += 7 { 2006 | if shift >= 64 { 2007 | return ErrIntOverflow 2008 | } 2009 | if iNdEx >= l { 2010 | return io.ErrUnexpectedEOF 2011 | } 2012 | b := dAtA[iNdEx] 2013 | iNdEx++ 2014 | stringLen |= uint64(b&0x7F) << shift 2015 | if b < 0x80 { 2016 | break 2017 | } 2018 | } 2019 | intStringLen := int(stringLen) 2020 | if intStringLen < 0 { 2021 | return ErrInvalidLength 2022 | } 2023 | postIndex := iNdEx + intStringLen 2024 | if postIndex < 0 { 2025 | return ErrInvalidLength 2026 | } 2027 | if postIndex > l { 2028 | return io.ErrUnexpectedEOF 2029 | } 2030 | m.MTalkAuthSecret = string(dAtA[iNdEx:postIndex]) 2031 | iNdEx = postIndex 2032 | default: 2033 | iNdEx = preIndex 2034 | skippy, err := skip(dAtA[iNdEx:]) 2035 | if err != nil { 2036 | return err 2037 | } 2038 | if (skippy < 0) || (iNdEx+skippy) < 0 { 2039 | return ErrInvalidLength 2040 | } 2041 | if (iNdEx + skippy) > l { 2042 | return io.ErrUnexpectedEOF 2043 | } 2044 | m.unknownFields = append(m.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) 2045 | iNdEx += skippy 2046 | } 2047 | } 2048 | 2049 | if iNdEx > l { 2050 | return io.ErrUnexpectedEOF 2051 | } 2052 | return nil 2053 | } 2054 | -------------------------------------------------------------------------------- /api/mcs.proto: -------------------------------------------------------------------------------- 1 | // Derived from mcs.proto in chromium source code. Original license text below. 2 | 3 | // Copyright 2013 The Chromium Authors. All rights reserved. 4 | // Use of this source code is governed by a BSD-style license that can be 5 | // found in the LICENSE file. 6 | // 7 | // MCS protocol for communication between Chrome client and Mobile Connection 8 | // Server . 9 | syntax = "proto2"; 10 | option java_package = "org.microg.gms.gcm.mcs"; 11 | option go_package = "github.com/BRUHItsABunny/go-android-firebase/firebase_api"; 12 | 13 | enum MCSTag { 14 | MCS_HEARTBEAT_PING_TAG = 0; 15 | MCS_HEARTBEAT_ACK_TAG = 1; 16 | MCS_LOGIN_REQUEST_TAG = 2; 17 | MCS_LOGIN_RESPONSE_TAG = 3; 18 | MCS_CLOSE_TAG = 4; 19 | MCS_IQ_STANZA_TAG = 7; 20 | MCS_DATA_MESSAGE_STANZA_TAG = 8; 21 | } 22 | 23 | /* 24 | Common fields/comments: 25 | 26 | stream_id: no longer sent by server, each side keeps a counter 27 | last_stream_id_received: sent only if a packet was received since last time 28 | a last_stream was sent 29 | status: new bitmask including the 'idle' as bit 0. 30 | 31 | */ 32 | 33 | /** 34 | TAG: 0 35 | */ 36 | message HeartbeatPing { 37 | optional int32 stream_id = 1; 38 | optional int32 last_stream_id_received = 2; 39 | optional int64 status = 3; 40 | } 41 | 42 | /** 43 | TAG: 1 44 | */ 45 | message HeartbeatAck { 46 | optional int32 stream_id = 1; 47 | optional int32 last_stream_id_received = 2; 48 | optional int64 status = 3; 49 | } 50 | 51 | message ErrorInfo { 52 | required int32 code = 1; 53 | optional string message = 2; 54 | optional string type = 3; 55 | optional Extension extension = 4; 56 | } 57 | 58 | // MobileSettings class. 59 | // "u:f", "u:b", "u:s" - multi user devices reporting foreground, background 60 | // and stopped users. 61 | // hbping: heatbeat ping interval 62 | // rmq2v: include explicit stream IDs 63 | 64 | message Setting { 65 | required string name = 1; 66 | required string value = 2; 67 | } 68 | 69 | message HeartbeatStat { 70 | required string ip = 1; 71 | required bool timeout = 2; 72 | required int32 interval_ms = 3; 73 | } 74 | 75 | message HeartbeatConfig { 76 | optional bool upload_stat = 1; 77 | optional string ip = 2; 78 | optional int32 interval_ms = 3; 79 | } 80 | 81 | /** 82 | TAG: 2 83 | */ 84 | message LoginRequest { 85 | enum AuthService { 86 | ANDROID_ID = 2; 87 | } 88 | required string id = 1; // Must be present ( proto required ), may be empty 89 | // string. 90 | // mcs.android.com. 91 | required string domain = 2; 92 | // Decimal android ID 93 | required string user = 3; 94 | 95 | required string resource = 4; 96 | 97 | // Secret 98 | required string auth_token = 5; 99 | 100 | // Format is: android-HEX_DEVICE_ID 101 | // The user is the decimal value. 102 | optional string device_id = 6; 103 | 104 | // RMQ1 - no longer used 105 | optional int64 last_rmq_id = 7; 106 | 107 | repeated Setting setting = 8; 108 | optional int32 compress = 9; 109 | repeated string received_persistent_id = 10; 110 | 111 | // Replaced by "rmq2v" setting 112 | optional bool include_stream_ids = 11; 113 | 114 | optional bool adaptive_heartbeat = 12; 115 | optional HeartbeatStat heartbeat_stat = 13; 116 | // Must be true. 117 | optional bool use_rmq2 = 14; 118 | optional int64 account_id = 15; 119 | 120 | // ANDROID_ID = 2 121 | optional AuthService auth_service = 16; 122 | 123 | optional int32 network_type = 17; 124 | optional int64 status = 18; 125 | } 126 | 127 | /** 128 | * TAG: 3 129 | */ 130 | message LoginResponse { 131 | required string id = 1; 132 | // Not used. 133 | optional string jid = 2; 134 | // Null if login was ok. 135 | optional ErrorInfo error = 3; 136 | repeated Setting setting = 4; 137 | optional int32 stream_id = 5; 138 | // Should be "1" 139 | optional int32 last_stream_id_received = 6; 140 | optional HeartbeatConfig heartbeat_config = 7; 141 | // used by the client to synchronize with the server timestamp. 142 | optional int64 server_timestamp = 8; 143 | } 144 | 145 | message StreamErrorStanza { 146 | required string type = 1; 147 | optional string text = 2; 148 | } 149 | 150 | /** 151 | * TAG: 4 152 | */ 153 | message Close { 154 | } 155 | 156 | message Extension { 157 | // 12: SelectiveAck 158 | // 13: StreamAck 159 | required int32 id = 1; 160 | required bytes data = 2; 161 | } 162 | 163 | /** 164 | * TAG: 7 165 | * IqRequest must contain a single extension. IqResponse may contain 0 or 1 166 | * extensions. 167 | */ 168 | message IqStanza { 169 | enum IqType { 170 | GET = 0; 171 | SET = 1; 172 | RESULT = 2; 173 | IQ_ERROR = 3; 174 | } 175 | 176 | optional int64 rmq_id = 1; 177 | required IqType type = 2; 178 | required string id = 3; 179 | optional string from = 4; 180 | optional string to = 5; 181 | optional ErrorInfo error = 6; 182 | 183 | // Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id) 184 | optional Extension extension = 7; 185 | 186 | optional string persistent_id = 8; 187 | optional int32 stream_id = 9; 188 | optional int32 last_stream_id_received = 10; 189 | optional int64 account_id = 11; 190 | optional int64 status = 12; 191 | } 192 | 193 | message AppData { 194 | required string key = 1; 195 | required string value = 2; 196 | } 197 | 198 | /** 199 | * TAG: 8 200 | */ 201 | message DataMessageStanza { 202 | // Not used. 203 | optional int64 rmq_id = 1; 204 | 205 | // This is the message ID, set by client, DMP.9 (message_id) 206 | optional string id = 2; 207 | 208 | // Project ID of the sender, DMP.1 209 | required string from = 3; 210 | 211 | // Part of DMRequest - also the key in DataMessageProto. 212 | optional string to = 4; 213 | 214 | // Package name. DMP.2 215 | required string category = 5; 216 | 217 | // The collapsed key, DMP.3 218 | optional string token = 6; 219 | 220 | // User data + GOOGLE. prefixed special entries, DMP.4 221 | repeated AppData app_data = 7; 222 | 223 | // Not used. 224 | optional bool from_trusted_server = 8; 225 | 226 | // Part of the ACK protocol, returned in DataMessageResponse on server side. 227 | // It's part of the key of DMP. 228 | optional string persistent_id = 9; 229 | 230 | // In-stream ack. Increments on each message sent - a bit redundant 231 | // Not used in DMP/DMR. 232 | optional int32 stream_id = 10; 233 | optional int32 last_stream_id_received = 11; 234 | 235 | // Not used. 236 | optional string permission = 12; 237 | 238 | // Sent by the device shortly after registration. 239 | optional string reg_id = 13; 240 | 241 | // Not used. 242 | optional string pkg_signature = 14; 243 | // Not used. 244 | optional string client_id = 15; 245 | 246 | // serial number of the target user, DMP.8 247 | // It is the 'serial number' according to user manager. 248 | optional int64 device_user_id = 16; 249 | 250 | // Time to live, in seconds. 251 | optional int32 ttl = 17; 252 | // Timestamp ( according to client ) when message was sent by app, in seconds 253 | optional int64 sent = 18; 254 | 255 | // How long has the message been queued before the flush, in seconds. 256 | // This is needed to account for the time difference between server and 257 | // client: server should adjust 'sent' based on his 'receive' time. 258 | optional int32 queued = 19; 259 | 260 | optional int64 status = 20; 261 | 262 | optional bytes raw_data = 21; 263 | 264 | optional int32 delay = 22; 265 | } 266 | 267 | /** 268 | Included in IQ with ID 13, sent from client or server after 10 unconfirmed 269 | messages. 270 | */ 271 | message StreamAck { 272 | // No last_streamid_received required. This is included within an IqStanza, 273 | // which includes the last_stream_id_received. 274 | } 275 | 276 | /** 277 | Included in IQ sent after LoginResponse from server with ID 12. 278 | */ 279 | message SelectiveAck { 280 | repeated string id = 1; 281 | } 282 | -------------------------------------------------------------------------------- /api/structs.go: -------------------------------------------------------------------------------- 1 | package firebase_api 2 | 3 | import ( 4 | "encoding/json" 5 | "strconv" 6 | "time" 7 | ) 8 | 9 | type NotifyInstallationRequestBody struct { 10 | FID string `json:"fid"` 11 | AppID string `json:"appId"` 12 | AuthVersion string `json:"authVersion"` 13 | SDKVersion string `json:"sdkVersion"` 14 | } 15 | 16 | type FireBaseInstallationResponse struct { 17 | Name string `json:"name"` 18 | FID string `json:"fid"` 19 | RefreshToken string `json:"refreshToken"` 20 | AuthToken FireBaseAuthToken `json:"authToken"` 21 | } 22 | 23 | type FireBaseAuthToken struct { 24 | Token string `json:"token"` 25 | Expiration string `json:"expiresin"` 26 | } 27 | 28 | /* 29 | type FirebaseDevice struct { 30 | Device *andutils.Device `json:"device"` 31 | // Other Firebase related constants... 32 | AndroidPackage string `json:"android_package"` 33 | AndroidCert string `json:"android_certificate"` 34 | GoogleAPIKey string `json:"google_api_key"` 35 | ProjectID string `json:"project_id"` 36 | GMPAppID string `json:"gmp_app_id"` 37 | // Also app specific constants but might be harder to find 38 | AppNameHash string `json:"app_name_hash"` 39 | NotificationSender string `json:"notification_sender"` 40 | AppVersion string `json:"app_version"` 41 | AppVersionWithBuild string `json:"app_version_with_build"` 42 | // Firebase Installation persistent variables 43 | FirebaseInstallationID string `json:"firebase_installation_id"` 44 | FirebaseInstallationAuth *FireBaseAuthToken `json:"firebase_installation_auth"` 45 | // Checkin related persistent variables 46 | CheckinAndroidID int64 `json:"checkin_android_id"` 47 | CheckinSecurityToken uint64 `json:"checkin_security_token"` 48 | } 49 | 50 | type FirebaseAuthentication struct { 51 | AccessToken string 52 | Expires time.Time 53 | RefreshToken string 54 | IDToken string 55 | } 56 | 57 | type auxFirebaseAuthentication struct { 58 | AccessToken string `json:"access_token"` 59 | ExpiresIn int64 `json:"expires_in"` 60 | RefreshToken string `json:"refresh_token"` 61 | IDToken string `json:"id_token"` 62 | } 63 | 64 | func (fa *FirebaseAuthentication) MarshalJSON() ([]byte, error) { 65 | return json.Marshal(&auxFirebaseAuthentication{ 66 | AccessToken: fa.AccessToken, 67 | ExpiresIn: fa.Expires.Unix(), 68 | RefreshToken: fa.RefreshToken, 69 | IDToken: fa.IDToken, 70 | }) 71 | } 72 | 73 | func (fa *FirebaseAuthentication) UnmarshalJSON(data []byte) error { 74 | aux := new(auxFirebaseAuthentication) 75 | err := json.Unmarshal(data, aux) 76 | if err == nil { 77 | fa.IDToken = aux.IDToken 78 | fa.RefreshToken = aux.RefreshToken 79 | if aux.ExpiresIn > 3600 { // If we store it 80 | fa.Expires = time.Unix(aux.ExpiresIn, 0) 81 | } else { // If we receive it from firebase 82 | fa.Expires = time.Now().Add(time.Duration(aux.ExpiresIn) * time.Second) 83 | } 84 | } 85 | return err 86 | } 87 | */ 88 | 89 | type SecureTokenRefreshResponse struct { 90 | AccessToken string 91 | Expires time.Time 92 | RefreshToken string 93 | IDToken string 94 | TokenType string 95 | UserID string 96 | ProjectID string 97 | } 98 | 99 | type AuthResponse struct { 100 | Token string 101 | Expires time.Time 102 | Metadata string 103 | Scopes []string 104 | } 105 | 106 | type auxSecureTokenRefreshResponse struct { 107 | AccessToken string 108 | ExpiresIn int64 109 | RefreshToken string 110 | IDToken string 111 | TokenType string 112 | UserID string 113 | ProjectID string 114 | } 115 | 116 | func (str *SecureTokenRefreshResponse) MarshalJSON() ([]byte, error) { 117 | return json.Marshal(&auxSecureTokenRefreshResponse{ 118 | AccessToken: str.AccessToken, 119 | ExpiresIn: str.Expires.Unix(), 120 | RefreshToken: str.RefreshToken, 121 | IDToken: str.IDToken, 122 | TokenType: str.TokenType, 123 | UserID: str.UserID, 124 | ProjectID: str.ProjectID, 125 | }) 126 | } 127 | 128 | func (str *SecureTokenRefreshResponse) UnmarshalJSON(data []byte) error { 129 | aux := new(auxSecureTokenRefreshResponse) 130 | err := json.Unmarshal(data, aux) 131 | if err == nil { 132 | str.UserID = aux.UserID 133 | str.ProjectID = aux.ProjectID 134 | str.TokenType = aux.TokenType 135 | str.AccessToken = aux.AccessToken 136 | str.IDToken = aux.IDToken 137 | str.RefreshToken = aux.RefreshToken 138 | if aux.ExpiresIn > 3600 { // If we store it 139 | str.Expires = time.Unix(aux.ExpiresIn, 0) 140 | } else { // If we receive it from firebase 141 | str.Expires = time.Now().Add(time.Duration(aux.ExpiresIn) * time.Second) 142 | } 143 | } 144 | return err 145 | } 146 | 147 | type ProviderUserInfo struct { 148 | ProviderID string `json:"providerId"` 149 | DisplayName string `json:"displayName"` 150 | FederateID string `json:"federateId"` 151 | Email string `json:"email,omitempty"` 152 | RawID string `json:"rawId"` 153 | } 154 | 155 | type GoogleSetAccountInfoResponse struct { 156 | Kind string `json:"kind"` 157 | Email string `json:"email"` 158 | LocalID string `json:"localId"` 159 | DisplayName string `json:"displayName"` 160 | ProviderUserInfo []*ProviderUserInfo `json:"providerUserInfo"` 161 | PasswordHash string `json:"passwordHash"` 162 | EmailVerified bool `json:"emailVerified"` 163 | } 164 | 165 | type GoogleVerifyPasswordResponse struct { 166 | Expires time.Time 167 | RefreshToken string 168 | IDToken string 169 | Kind string 170 | Email string 171 | LocalID string 172 | DisplayName string 173 | Registered bool 174 | } 175 | 176 | type auxGoogleVerifyPasswordResponse struct { 177 | ExpiresIn string `json:"expiresIn"` 178 | RefreshToken string `json:"refreshToken"` 179 | IDToken string `json:"idToken"` 180 | Kind string `json:"kind"` 181 | Email string `json:"email"` 182 | LocalID string `json:"localId"` 183 | DisplayName string `json:"displayName"` 184 | Registered bool `json:"registered"` 185 | } 186 | 187 | func (gvp *GoogleVerifyPasswordResponse) MarshalJSON() ([]byte, error) { 188 | return json.Marshal(&auxGoogleVerifyPasswordResponse{ 189 | ExpiresIn: strconv.FormatInt(gvp.Expires.Unix(), 10), 190 | RefreshToken: gvp.RefreshToken, 191 | IDToken: gvp.IDToken, 192 | Kind: gvp.Kind, 193 | Email: gvp.Email, 194 | LocalID: gvp.LocalID, 195 | DisplayName: gvp.DisplayName, 196 | Registered: gvp.Registered, 197 | }) 198 | } 199 | 200 | func (gvp *GoogleVerifyPasswordResponse) UnmarshalJSON(data []byte) error { 201 | var tmpExpiresIn int64 202 | aux := new(auxGoogleVerifyPasswordResponse) 203 | err := json.Unmarshal(data, aux) 204 | if err == nil { 205 | gvp.RefreshToken = aux.RefreshToken 206 | gvp.IDToken = aux.IDToken 207 | gvp.Kind = aux.Kind 208 | gvp.Email = aux.Email 209 | gvp.LocalID = aux.LocalID 210 | gvp.DisplayName = aux.DisplayName 211 | gvp.Registered = aux.Registered 212 | tmpExpiresIn, err = strconv.ParseInt(aux.ExpiresIn, 10, 64) 213 | if err == nil { 214 | if tmpExpiresIn > 3600 { // If we store it 215 | gvp.Expires = time.Unix(tmpExpiresIn, 0) 216 | } else { // If we receive it from firebase 217 | gvp.Expires = time.Now().Add(time.Duration(tmpExpiresIn) * time.Second) 218 | } 219 | } 220 | } 221 | return err 222 | } 223 | 224 | type GoogleSignUpNewUserResponse struct { 225 | Expires time.Time 226 | RefreshToken string 227 | IDToken string 228 | Kind string 229 | Email string 230 | LocalID string 231 | } 232 | 233 | type auxGoogleSignUpNewUserResponse struct { 234 | ExpiresIn string 235 | RefreshToken string 236 | IDToken string 237 | Kind string 238 | Email string 239 | LocalID string 240 | } 241 | 242 | func (gsp *GoogleSignUpNewUserResponse) MarshalJSON() ([]byte, error) { 243 | return json.Marshal(&auxGoogleSignUpNewUserResponse{ 244 | ExpiresIn: strconv.FormatInt(gsp.Expires.Unix(), 10), 245 | RefreshToken: gsp.RefreshToken, 246 | IDToken: gsp.IDToken, 247 | Kind: gsp.Kind, 248 | Email: gsp.Email, 249 | LocalID: gsp.LocalID, 250 | }) 251 | } 252 | 253 | func (gsp *GoogleSignUpNewUserResponse) UnmarshalJSON(data []byte) error { 254 | var tmpExpiresIn int64 255 | aux := new(auxGoogleSignUpNewUserResponse) 256 | err := json.Unmarshal(data, aux) 257 | if err == nil { 258 | gsp.RefreshToken = aux.RefreshToken 259 | gsp.IDToken = aux.IDToken 260 | gsp.Kind = aux.Kind 261 | gsp.Email = aux.Email 262 | gsp.LocalID = aux.LocalID 263 | tmpExpiresIn, err = strconv.ParseInt(aux.ExpiresIn, 10, 64) 264 | if err == nil { 265 | if tmpExpiresIn > 3600 { // If we store it 266 | gsp.Expires = time.Unix(tmpExpiresIn, 0) 267 | } else { // If we receive it from firebase 268 | gsp.Expires = time.Now().Add(time.Duration(tmpExpiresIn) * time.Second) 269 | } 270 | } 271 | } 272 | return err 273 | } 274 | 275 | type FirebaseRequest struct { 276 | ReturnSecureToken bool `json:"returnSecureToken"` 277 | AuthToken string `json:"idToken,omitempty"` 278 | } 279 | 280 | type SetAccountInfoRequestBody struct { 281 | FirebaseRequest 282 | Data map[string]interface{} 283 | } 284 | 285 | func (sai *SetAccountInfoRequestBody) MarshalJSON() ([]byte, error) { 286 | targetMap := make(map[string]interface{}) 287 | for k, v := range sai.Data { 288 | targetMap[k] = v 289 | } 290 | if len(sai.AuthToken) > 0 { 291 | targetMap["idToken"] = sai.AuthToken 292 | } 293 | targetMap["returnSecureToken"] = sai.ReturnSecureToken 294 | 295 | return json.Marshal(&targetMap) 296 | } 297 | 298 | func (sai *SetAccountInfoRequestBody) UnmarshalJSON(data []byte) error { 299 | targetMap := make(map[string]interface{}) 300 | err := json.Unmarshal(data, &targetMap) 301 | if err == nil { 302 | returnSecureToken, ok := targetMap["returnSecureToken"] 303 | if ok { 304 | switch value := returnSecureToken.(type) { 305 | case bool: 306 | sai.ReturnSecureToken = value 307 | break 308 | } 309 | } 310 | 311 | idToken, ok := targetMap["idToken"] 312 | if ok { 313 | switch value := idToken.(type) { 314 | case string: 315 | sai.AuthToken = value 316 | break 317 | } 318 | } 319 | delete(targetMap, "idToken") 320 | delete(targetMap, "returnSecureToken") 321 | sai.Data = targetMap 322 | } 323 | return err 324 | } 325 | 326 | type VerifyPasswordRequestBody struct { 327 | Email string `json:"email"` 328 | Password string `json:"password"` 329 | ReturnSecureToken bool `json:"returnSecureToken"` 330 | } 331 | 332 | type SignUpNewUserRequestBody struct { 333 | Email string `json:"email"` 334 | Password string `json:"password"` 335 | } 336 | 337 | type RefreshSecureTokenRequestBody struct { 338 | GrantType string `json:"grantType"` 339 | RefreshToken string `json:"refreshToken"` 340 | } 341 | -------------------------------------------------------------------------------- /api/utils.go: -------------------------------------------------------------------------------- 1 | package firebase_api 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/binary" 6 | "fmt" 7 | . "github.com/BRUHItsABunny/go-android-firebase/constants" 8 | andutils "github.com/BRUHItsABunny/go-android-utils" 9 | "github.com/google/uuid" 10 | "math/big" 11 | "math/rand" 12 | "net/http" 13 | "strconv" 14 | "strings" 15 | ) 16 | 17 | func DefaultHeadersFirebase(device *FirebaseDevice, appData *FirebaseAppData, includeAPIKey, includeFireBaseClient, includeClientVersion bool) http.Header { 18 | headers := http.Header{ 19 | HeaderKeyContentType: {HeaderValueMIMEJSON}, 20 | HeaderKeyAccept: {HeaderValueMIMEJSON}, 21 | HeaderKeyCacheControl: {"no-cache"}, 22 | HeaderKeyAndroidCert: {strings.ToUpper(appData.PackageCertificate)}, 23 | HeaderKeyAndroidPackage: {appData.PackageID}, 24 | HeaderKeyUserAgent: {"Dalvik/2.1.0 " + device.Device.GetUserAgent()}, 25 | } 26 | 27 | if includeAPIKey { 28 | headers[HeaderKeyGoogAPIKey] = []string{appData.GoogleAPIKey} 29 | } 30 | if includeFireBaseClient { 31 | headers[HeaderKeyFireBaseClient] = []string{device.Device.FormatUserAgent(HeaderValueFireBaseClient)} 32 | } 33 | if includeClientVersion { 34 | // TODO: Constant or variable? 35 | headers[HeaderKeyClientVersion] = []string{HeaderValueClientVersion} 36 | } 37 | return headers 38 | } 39 | 40 | func DefaultHeadersAuth(device *andutils.Device) http.Header { 41 | headers := http.Header{ 42 | HeaderKeyContentType: {"application/x-www-form-urlencoded"}, 43 | "app": {"com.google.android.gm"}, 44 | "device": {device.Id.ToHexString()}, 45 | HeaderKeyUserAgent: {device.FormatUserAgent(fmt.Sprintf("GoogleAuth/1.4 (%s %s); gzip", andutils.DeviceFormatKeyModel, andutils.DeviceFormatKeyBuild))}, 46 | } 47 | 48 | return headers 49 | } 50 | 51 | func DefaultHeadersCheckin(device *andutils.Device) http.Header { 52 | headers := http.Header{ 53 | HeaderKeyContentType: {"application/x-protobuffer"}, 54 | HeaderKeyUserAgent: {device.FormatUserAgent(fmt.Sprintf("Android-Checkin/2.0 (%s %s); gzip", andutils.DeviceFormatKeyDevice, andutils.DeviceFormatKeyBuild))}, 55 | } 56 | 57 | return headers 58 | } 59 | 60 | func DefaultHeadersAndroidRegister(device *FirebaseDevice) http.Header { 61 | headers := http.Header{ 62 | HeaderKeyContentType: {"application/x-www-form-urlencoded"}, 63 | HeaderKeyUserAgent: {device.Device.FormatUserAgent(fmt.Sprintf("Android-GCM/1.5 (%s %s)", andutils.DeviceFormatKeyDevice, andutils.DeviceFormatKeyBuild))}, 64 | "Authorization": {fmt.Sprintf("AidLogin %d:%d", device.CheckinAndroidID, device.CheckinSecurityToken)}, 65 | } 66 | return headers 67 | } 68 | 69 | func FailSafeRandomAppFID() string { 70 | // Mimic: https://firebase.google.com/docs/reference/android/com/google/firebase/installations/FirebaseInstallations#public-taskstring-getid 71 | // url-safe base64 of 128bit integer as bytes, our approach 16 random bytes 72 | fakeInt := make([]byte, 16) 73 | rand.Read(fakeInt) 74 | return base64.RawURLEncoding.EncodeToString(fakeInt) 75 | } 76 | 77 | // GetLeastMostSignificantBits src: (Python) https://stackoverflow.com/a/40141219 78 | func GetLeastMostSignificantBits(uuidStr string) (int64, int64) { 79 | uuidSplit := strings.Split(uuidStr, "-") 80 | leastStr, mostStr := "", "" 81 | for i, subStr := range uuidSplit { 82 | if i <= 2 { 83 | mostStr += subStr 84 | } else { 85 | leastStr += subStr 86 | } 87 | } 88 | 89 | subTractor := new(big.Int) 90 | subTractor.SetString("10000000000000000", 16) 91 | leastBitsB := new(big.Int) 92 | leastBitsB.SetString(leastStr, 16) 93 | mostBitsB := new(big.Int) 94 | mostBitsB.SetString(mostStr, 16) 95 | 96 | leastBitsSign, _ := strconv.ParseInt(string(leastStr[0]), 16, 64) 97 | mostBitsSign, _ := strconv.ParseInt(string(mostStr[0]), 16, 64) 98 | 99 | var ( 100 | leastBits, mostBits int64 101 | ) 102 | if leastBitsSign > 7 { 103 | leastPostB := big.NewInt(0).Sub(leastBitsB, subTractor) 104 | leastBits = leastPostB.Int64() 105 | } else { 106 | leastBits = leastBitsB.Int64() 107 | } 108 | 109 | if mostBitsSign > 7 { 110 | mostPostB := big.NewInt(0).Sub(mostBitsB, subTractor) 111 | mostBits = mostPostB.Int64() 112 | } else { 113 | mostBits = mostBitsB.Int64() 114 | } 115 | 116 | return leastBits, mostBits 117 | } 118 | 119 | func RandomAppFID() (string, error) { 120 | // Mimic: https://github.com/firebase/firebase-android-sdk/blob/9dec703a90767e1646466d2786ddda2b25201d84/firebase-installations/src/main/java/com/google/firebase/installations/RandomFidGenerator.java#L23 121 | // Fixes FID in != FID out, YAY! 122 | fid := "" 123 | uuidObj, err := uuid.NewRandom() 124 | if err == nil { 125 | leastBits, mostBits := GetLeastMostSignificantBits(uuidObj.String()) 126 | uuidBytes := make([]byte, 17) 127 | // src: https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html 128 | // "The order of a newly-created byte buffer is always BIG_ENDIAN." 129 | binary.BigEndian.PutUint64(uuidBytes[:8], uint64(mostBits)) 130 | binary.BigEndian.PutUint64(uuidBytes[8:16], uint64(leastBits)) 131 | uuidBytes[16] = uuidBytes[0] 132 | // Byte.parseByte("00001111", 2); = 15 133 | // Byte.parseByte("01110000", 2); = 112 134 | uuidBytes[0] = (15 & uuidBytes[0]) | 112 135 | fid = base64.URLEncoding.EncodeToString(uuidBytes)[:22] 136 | } else { 137 | fid = FailSafeRandomAppFID() 138 | } 139 | 140 | return fid, err 141 | } 142 | -------------------------------------------------------------------------------- /client/client.go: -------------------------------------------------------------------------------- 1 | package firebase_client 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | firebase_api "github.com/BRUHItsABunny/go-android-firebase/api" 7 | andutils "github.com/BRUHItsABunny/go-android-utils" 8 | "google.golang.org/protobuf/types/known/timestamppb" 9 | "net/http" 10 | "net/url" 11 | "strconv" 12 | "time" 13 | ) 14 | 15 | type FireBaseClient struct { 16 | Client *http.Client 17 | Device *firebase_api.FirebaseDevice 18 | MTalk *MTalkCon 19 | } 20 | 21 | func NewFirebaseClient(client *http.Client, device *firebase_api.FirebaseDevice) (*FireBaseClient, error) { 22 | if client == nil { 23 | client = http.DefaultClient 24 | } 25 | if device == nil { 26 | device = &firebase_api.FirebaseDevice{} 27 | } 28 | if device.Device == nil { 29 | device.Device = andutils.GetRandomDevice() 30 | } 31 | mTalk, err := NewMTalkCon(device) 32 | if err != nil { 33 | err = fmt.Errorf("NewMTalkCon: %w", err) 34 | return nil, err 35 | } 36 | 37 | return &FireBaseClient{ 38 | Client: client, 39 | Device: device, 40 | MTalk: mTalk, 41 | }, nil 42 | } 43 | 44 | func (c *FireBaseClient) NotifyInstallation(ctx context.Context, appData *firebase_api.FirebaseAppData) (*firebase_api.FireBaseInstallationResponse, error) { 45 | req, err := firebase_api.NotifyInstallationRequest(ctx, c.Device, appData) 46 | if err != nil { 47 | return nil, fmt.Errorf("api.NotifyInstallationRequest: %w", err) 48 | } 49 | 50 | resp, err := c.Client.Do(req) 51 | if err != nil { 52 | return nil, fmt.Errorf("c.Client.Do: %w", err) 53 | } 54 | 55 | result, err := firebase_api.NotifyInstallationResult(resp) 56 | if err != nil { 57 | return nil, fmt.Errorf("api.NotifyInstallationResult: %w", err) 58 | } 59 | 60 | if result == nil { 61 | return nil, fmt.Errorf("firebase_api.NotifyInstallationResult: nil result") 62 | } 63 | if len(result.AuthToken.Expiration) < 1 { 64 | return nil, fmt.Errorf("firebase_api.NotifyInstallationResult: invalid auth token") 65 | } 66 | 67 | if c.Device.FirebaseInstallations == nil { 68 | c.Device.FirebaseInstallations = map[string]*firebase_api.FirebaseInstallationData{} 69 | } 70 | installation, ok := c.Device.FirebaseInstallations[appData.PackageID] 71 | if !ok { 72 | installation = &firebase_api.FirebaseInstallationData{NotificationData: &firebase_api.FirebaseNotificationData{}} 73 | } 74 | 75 | expiresIn, _ := strconv.Atoi(result.AuthToken.Expiration[:len(result.AuthToken.Expiration)-1]) 76 | installation.InstallationAuthentication = &firebase_api.FirebaseAuthentication{ 77 | AccessToken: result.AuthToken.Token, 78 | Expires: timestamppb.New(time.Now().Add(time.Duration(expiresIn) * time.Second)), 79 | RefreshToken: result.RefreshToken, 80 | IdToken: "", 81 | } 82 | installation.FirebaseInstallationID = result.FID // FID in should equal FID out, but not always the case, override with FID out to be sure 83 | c.Device.FirebaseInstallations[appData.PackageID] = installation 84 | return result, err 85 | } 86 | 87 | func (c *FireBaseClient) VerifyPassword(ctx context.Context, data *firebase_api.VerifyPasswordRequestBody, appData *firebase_api.FirebaseAppData) (*firebase_api.GoogleVerifyPasswordResponse, error) { 88 | req, err := firebase_api.VerifyPasswordRequest(ctx, c.Device, appData, data) 89 | if err != nil { 90 | return nil, fmt.Errorf("api.VerifyPasswordRequest: %w", err) 91 | } 92 | 93 | resp, err := c.Client.Do(req) 94 | if err != nil { 95 | return nil, fmt.Errorf("c.Client.Do: %w", err) 96 | } 97 | 98 | result, err := firebase_api.VerifyPasswordResult(resp) 99 | if err != nil { 100 | return nil, fmt.Errorf("api.VerifyPasswordResult: %w", err) 101 | } 102 | return result, err 103 | } 104 | 105 | func (c *FireBaseClient) SetAccountInfo(ctx context.Context, appData *firebase_api.FirebaseAppData, data *firebase_api.SetAccountInfoRequestBody) (*firebase_api.GoogleSetAccountInfoResponse, error) { 106 | req, err := firebase_api.SetAccountInfoRequest(ctx, c.Device, appData, data) 107 | if err != nil { 108 | return nil, fmt.Errorf("api.SetAccountInfoRequest: %w", err) 109 | } 110 | 111 | resp, err := c.Client.Do(req) 112 | if err != nil { 113 | return nil, fmt.Errorf("c.Client.Do: %w", err) 114 | } 115 | 116 | result, err := firebase_api.SetAccountInfoResult(resp) 117 | if err != nil { 118 | return nil, fmt.Errorf("api.SetAccountInfoResult: %w", err) 119 | } 120 | return result, err 121 | } 122 | 123 | func (c *FireBaseClient) SignUpNewUser(ctx context.Context, appData *firebase_api.FirebaseAppData, data *firebase_api.SignUpNewUserRequestBody) (*firebase_api.GoogleSignUpNewUserResponse, error) { 124 | var ( 125 | result = new(firebase_api.GoogleSignUpNewUserResponse) 126 | req *http.Request 127 | resp *http.Response 128 | err error 129 | ) 130 | 131 | req, err = firebase_api.SignUpNewUser(ctx, c.Device, appData, data) 132 | if err == nil { 133 | resp, err = c.Client.Do(req) 134 | if err == nil { 135 | result, err = firebase_api.SignUpNewUserResult(resp) 136 | } 137 | } 138 | return result, err 139 | } 140 | 141 | func (c *FireBaseClient) RefreshSecureToken(ctx context.Context, appData *firebase_api.FirebaseAppData, data *firebase_api.RefreshSecureTokenRequestBody) (*firebase_api.SecureTokenRefreshResponse, error) { 142 | req, err := firebase_api.RefreshSecureTokenRequest(ctx, c.Device, appData, data) 143 | if err != nil { 144 | return nil, fmt.Errorf("api.RefreshSecureTokenRequest: %w", err) 145 | } 146 | 147 | resp, err := c.Client.Do(req) 148 | if err != nil { 149 | return nil, fmt.Errorf("c.Client.Do: %w", err) 150 | } 151 | 152 | result, err := firebase_api.RefreshSecureTokenResult(resp) 153 | if err != nil { 154 | return nil, fmt.Errorf("api.RefreshSecureTokenResult: %w", err) 155 | } 156 | return result, err 157 | } 158 | 159 | func (c *FireBaseClient) Auth(ctx context.Context, appData *firebase_api.FirebaseAppData, data url.Values, email, token string) (*firebase_api.AuthResponse, error) { 160 | 161 | if email != "" { 162 | data["Email"] = []string{email} 163 | 164 | } 165 | if token != "" { 166 | data["Token"] = []string{token} 167 | } 168 | 169 | req, err := firebase_api.AuthRequest(ctx, c.Device.Device, appData, data) 170 | if err != nil { 171 | return nil, fmt.Errorf("api.AuthRequest: %w", err) 172 | } 173 | 174 | resp, err := c.Client.Do(req) 175 | if err != nil { 176 | return nil, fmt.Errorf("c.Client.Do: %w", err) 177 | } 178 | 179 | result, err := firebase_api.AuthResult(resp) 180 | if err != nil { 181 | return nil, fmt.Errorf("api.AuthResult: %w", err) 182 | } 183 | return result, err 184 | } 185 | 186 | func (c *FireBaseClient) Checkin(ctx context.Context, appData *firebase_api.FirebaseAppData, digest, otaCert string, accountCookies ...string) (*firebase_api.CheckinResponse, error) { 187 | req, err := firebase_api.CheckinAndroidRequest(ctx, c.Device, appData, digest, otaCert, accountCookies...) 188 | if err != nil { 189 | return nil, fmt.Errorf("api.CheckinAndroidRequest: %w", err) 190 | } 191 | 192 | resp, err := c.Client.Do(req) 193 | if err != nil { 194 | return nil, fmt.Errorf("c.Client.Do: %w", err) 195 | } 196 | 197 | result, err := firebase_api.CheckinResult(resp) 198 | if err != nil { 199 | return nil, fmt.Errorf("api.CheckinResult: %w", err) 200 | } 201 | c.Device.CheckinAndroidID = int64(*result.AndroidId) 202 | c.Device.CheckinSecurityToken = *result.SecurityToken 203 | return result, err 204 | } 205 | 206 | func (c *FireBaseClient) C2DMRegisterAndroid(ctx context.Context, appData *firebase_api.FirebaseAppData) (string, error) { 207 | req, err := firebase_api.C2DMAndroidRegisterRequest(ctx, c.Device, appData) 208 | if err != nil { 209 | return "", fmt.Errorf("api.C2DMAndroidRegisterRequest: %w", err) 210 | } 211 | 212 | resp, err := c.Client.Do(req) 213 | if err != nil { 214 | return "", fmt.Errorf("c.Client.Do: %w", err) 215 | } 216 | 217 | result, err := firebase_api.AndroidRegisterResult(resp) 218 | if err != nil { 219 | return "", fmt.Errorf("api.AndroidRegisterResult: %w", err) 220 | } 221 | if c.Device.FirebaseInstallations == nil { 222 | c.Device.FirebaseInstallations = map[string]*firebase_api.FirebaseInstallationData{} 223 | } 224 | installation, ok := c.Device.FirebaseInstallations[appData.PackageID] 225 | if !ok { 226 | installation = &firebase_api.FirebaseInstallationData{NotificationData: &firebase_api.FirebaseNotificationData{}} 227 | } 228 | installation.NotificationData.NotificationToken = result 229 | c.Device.FirebaseInstallations[appData.PackageID] = installation 230 | return result, err 231 | } 232 | 233 | func (c *FireBaseClient) C2DMRegisterWeb(ctx context.Context, appData *firebase_api.FirebaseAppData, sender, subtype, appid string) (string, error) { 234 | req, err := firebase_api.C2DMWebRegisterRequest(ctx, c.Device, appData, sender, subtype, appid) 235 | if err != nil { 236 | return "", fmt.Errorf("api.C2DMWebRegisterRequest: %w", err) 237 | } 238 | 239 | resp, err := c.Client.Do(req) 240 | if err != nil { 241 | return "", fmt.Errorf("c.Client.Do: %w", err) 242 | } 243 | 244 | result, err := firebase_api.AndroidRegisterResult(resp) 245 | if err != nil { 246 | return "", fmt.Errorf("api.AndroidRegisterResult: %w", err) 247 | } 248 | // TODO: Store subscription (notification token) somewhere? 249 | return result, err 250 | } 251 | -------------------------------------------------------------------------------- /client/mtalk.go: -------------------------------------------------------------------------------- 1 | package firebase_client 2 | 3 | import ( 4 | "crypto/ecdh" 5 | "crypto/rand" 6 | "crypto/tls" 7 | "encoding/base64" 8 | "encoding/json" 9 | "errors" 10 | "fmt" 11 | firebase_api "github.com/BRUHItsABunny/go-android-firebase/api" 12 | "github.com/BRUHItsABunny/go-android-firebase/constants" 13 | "github.com/davecgh/go-spew/spew" 14 | "github.com/xakep666/ecego" 15 | "go.uber.org/atomic" 16 | "google.golang.org/protobuf/proto" 17 | "io" 18 | "net" 19 | "strconv" 20 | "strings" 21 | "sync" 22 | ) 23 | 24 | type MTalkMessageProcessor func(message proto.Message) 25 | type MTalkNotificationProcessor func(notification *firebase_api.DataMessageStanza) 26 | 27 | type MTalkCon struct { 28 | RawConn net.Conn 29 | sync.WaitGroup 30 | OnMessage MTalkMessageProcessor 31 | OnNotification MTalkNotificationProcessor 32 | lastPersistentId string 33 | streamIdReported int 34 | streamId int 35 | stop *atomic.Bool 36 | Device *firebase_api.FirebaseDevice 37 | ECEEngine *ecego.Engine 38 | } 39 | 40 | const MTalkVersion = byte(41) 41 | 42 | var ( 43 | mapEncryptionSchemes = map[string]ecego.Version{ 44 | string(ecego.AES128GCM): ecego.AES128GCM, 45 | string(ecego.AESGCM): ecego.AESGCM, 46 | string(ecego.AESGCM128): ecego.AESGCM128, 47 | } 48 | ) 49 | 50 | func NewMTalkCon(device *firebase_api.FirebaseDevice) (*MTalkCon, error) { 51 | result := &MTalkCon{stop: atomic.NewBool(false), Device: device} 52 | result.OnMessage = result.defaultOnMessage 53 | result.OnNotification = result.defaultOnNotification 54 | 55 | var ( 56 | authSecret = make([]byte, 16) 57 | privateKey *ecdh.PrivateKey 58 | err error 59 | ) 60 | if device.MTalkAuthSecret != "" { 61 | authSecret, err = base64.RawURLEncoding.DecodeString(device.MTalkAuthSecret) 62 | if err != nil { 63 | err = fmt.Errorf("base64.RawURLEncoding.DecodeString[authSecret]: %w", err) 64 | return nil, err 65 | } 66 | } else { 67 | _, err = rand.Read(authSecret) 68 | if err != nil { 69 | err = fmt.Errorf("rand.Read[authSecret]: %w", err) 70 | return nil, err 71 | } 72 | device.MTalkAuthSecret = base64.RawURLEncoding.EncodeToString(authSecret) 73 | } 74 | if device.MTalkPrivateKey != "" { 75 | privateKeyBytes, err := base64.RawURLEncoding.DecodeString(device.MTalkAuthSecret) 76 | if err != nil { 77 | err = fmt.Errorf("base64.RawURLEncoding.DecodeString[privateKey]: %w", err) 78 | return nil, err 79 | } 80 | privateKey, err = ecdh.P256().NewPrivateKey(privateKeyBytes) 81 | if err != nil { 82 | err = fmt.Errorf("ecdh.P256().NewPrivateKey: %w", err) 83 | return nil, err 84 | } 85 | device.MTalkPublicKey = base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes()) 86 | } else { 87 | privateKey, err = ecdh.P256().GenerateKey(rand.Reader) 88 | if err != nil { 89 | err = fmt.Errorf("ecdh.P256().GenerateKey: %w", err) 90 | return nil, err 91 | } 92 | device.MTalkPublicKey = base64.RawURLEncoding.EncodeToString(privateKey.Bytes()) 93 | device.MTalkPublicKey = base64.RawURLEncoding.EncodeToString(privateKey.PublicKey().Bytes()) 94 | } 95 | 96 | result.ECEEngine = ecego.NewEngine(ecego.SingleKey(privateKey), ecego.WithAuthSecret(authSecret)) 97 | return result, nil 98 | } 99 | 100 | func (c *MTalkCon) Connect() error { 101 | // Connect 102 | connV2, err := tls.Dial("tcp", fmt.Sprintf("%s:%s", constants.MTalkHost, constants.MTalkPort), nil) 103 | if err != nil { 104 | return fmt.Errorf("tls.Dial: %w", err) 105 | } 106 | c.RawConn = connV2 107 | 108 | // login 109 | err = c.writeByte(MTalkVersion) // Write version first 110 | if err != nil { 111 | return fmt.Errorf("c.writeByte[version]: %w", err) 112 | } 113 | 114 | err = c.login() 115 | if err != nil { 116 | return fmt.Errorf("result.login: %w", err) 117 | } 118 | 119 | version, err := c.readByte() // read version 120 | if err != nil { 121 | return fmt.Errorf("c.readByte[version]: %w", err) 122 | } 123 | 124 | if version != MTalkVersion { 125 | return errors.New("mtalk version not consistent") 126 | } 127 | // fmt.Println(fmt.Sprintf("version: %d", version)) 128 | 129 | loginResp, err := c.readMessage() 130 | if err != nil { 131 | return fmt.Errorf("result.readMessage: %w", err) 132 | } 133 | loginRespParsed, ok := loginResp.(*firebase_api.LoginResponse) 134 | if !ok { 135 | return errors.New("didn't receive login response") 136 | } 137 | if loginRespParsed.Error != nil { 138 | return errors.New(*loginRespParsed.Error.Message) 139 | } 140 | // Start goroutine to read in background and notify us? 141 | c.Add(1) 142 | go c.loop() 143 | return nil 144 | } 145 | 146 | func (c *MTalkCon) loop() { 147 | for { 148 | msg, err := c.readMessage() 149 | if err != nil { 150 | panic(err) 151 | } 152 | c.OnMessage(msg) 153 | if c.stop.Load() { 154 | break 155 | } 156 | } 157 | c.Done() 158 | } 159 | 160 | func (c *MTalkCon) defaultOnMessage(msg proto.Message) { 161 | switch parsedMsg := msg.(type) { 162 | case *firebase_api.HeartbeatPing: 163 | response := &firebase_api.HeartbeatAck{ 164 | Status: parsedMsg.Status, 165 | } 166 | if c.streamId != c.streamIdReported { 167 | c.streamIdReported = c.streamId 168 | response.LastStreamIdReceived = proto.Int32(int32(c.streamIdReported)) 169 | } 170 | err := c.writeMessage(firebase_api.MCSTag_MCS_HEARTBEAT_ACK_TAG, response) 171 | if err != nil { 172 | err = fmt.Errorf("c.writeMessage[PingAck]: %w", err) 173 | panic(err) 174 | } 175 | break 176 | case *firebase_api.DataMessageStanza: 177 | if parsedMsg.PersistentId != nil { 178 | c.Device.MTalkLastPersistentId = *parsedMsg.PersistentId 179 | } 180 | 181 | // What encryption scheme is it using 182 | var err error 183 | encryptionParams := ecego.OperationalParams{} 184 | parsedAppData := map[string]string{} 185 | for _, appData := range parsedMsg.AppData { 186 | key := strings.ToLower(appData.GetKey()) 187 | parsedAppData[key] = appData.GetValue() 188 | if key == "content-encoding" { 189 | encryptionParams.Version, _ = mapEncryptionSchemes[appData.GetValue()] 190 | } 191 | } 192 | // Parse params for scheme 193 | switch encryptionParams.Version { 194 | case ecego.AESGCM128: 195 | fallthrough 196 | case ecego.AESGCM: 197 | encryptionAppData, ok := parsedAppData["encryption"] 198 | if ok { 199 | encryptionAppDataDecoded := parseAppDataValue(encryptionAppData) 200 | saltStr, ok := encryptionAppDataDecoded["salt"] 201 | if ok { 202 | encryptionParams.Salt, err = base64.RawURLEncoding.DecodeString(saltStr) 203 | if err != nil { 204 | err = fmt.Errorf("base64.RawURLEncoding.DecodeString[%s:salt]: %w", string(encryptionParams.Version), err) 205 | panic(err) 206 | } 207 | } 208 | } 209 | cryptoKeyAppData, ok := parsedAppData["crypto-key"] 210 | if ok { 211 | cryptoKeyAppDataDecoded := parseAppDataValue(cryptoKeyAppData) 212 | dhStr, ok := cryptoKeyAppDataDecoded["dh"] 213 | if ok { 214 | encryptionParams.DH, err = base64.RawURLEncoding.DecodeString(dhStr) 215 | if err != nil { 216 | err = fmt.Errorf("base64.RawURLEncoding.DecodeString[%s:dh]: %w", string(encryptionParams.Version), err) 217 | panic(err) 218 | } 219 | } 220 | } 221 | 222 | parsedRawData := map[string]string{} 223 | err = json.Unmarshal(parsedMsg.RawData, &parsedRawData) 224 | if err == nil { 225 | rawData, ok := parsedRawData["raw_data"] 226 | if ok { 227 | rawDataBytes, err := base64.StdEncoding.DecodeString(rawData) 228 | if err != nil { 229 | parsedMsg.RawData = rawDataBytes 230 | } 231 | } 232 | } 233 | break 234 | } 235 | 236 | // Decrypt and replace raw data 237 | if encryptionParams.Version != "" { 238 | plaintext, err := c.ECEEngine.Decrypt(parsedMsg.RawData, nil, encryptionParams) 239 | if err != nil { 240 | err = fmt.Errorf("c.ECEEngine.Decrypt[%s]: %w", string(encryptionParams.Version), err) 241 | panic(err) 242 | } 243 | parsedMsg.RawData = plaintext 244 | } 245 | 246 | c.OnNotification(parsedMsg) 247 | break 248 | } 249 | } 250 | 251 | func (c *MTalkCon) defaultOnNotification(notification *firebase_api.DataMessageStanza) { 252 | fmt.Println(spew.Sdump(notification)) 253 | } 254 | 255 | func (c *MTalkCon) readMessage() (proto.Message, error) { 256 | tag, err := c.readByte() 257 | if err != nil { 258 | return nil, fmt.Errorf("c.readByte: %w", err) 259 | } 260 | length, err := c.readVarInt() 261 | if err != nil { 262 | return nil, fmt.Errorf("c.readVarInt: %w", err) 263 | } 264 | data, err := c.readBytes(length) 265 | if err != nil { 266 | return nil, fmt.Errorf("c.readBytes data: %w", err) 267 | } 268 | var result proto.Message 269 | switch firebase_api.MCSTag(int(tag)) { 270 | case firebase_api.MCSTag_MCS_HEARTBEAT_PING_TAG: 271 | result = &firebase_api.HeartbeatPing{} 272 | break 273 | case firebase_api.MCSTag_MCS_HEARTBEAT_ACK_TAG: 274 | result = &firebase_api.HeartbeatAck{} 275 | break 276 | case firebase_api.MCSTag_MCS_LOGIN_REQUEST_TAG: 277 | result = &firebase_api.LoginRequest{} 278 | break 279 | case firebase_api.MCSTag_MCS_LOGIN_RESPONSE_TAG: 280 | result = &firebase_api.LoginResponse{} 281 | break 282 | case firebase_api.MCSTag_MCS_CLOSE_TAG: 283 | result = &firebase_api.Close{} 284 | break 285 | case firebase_api.MCSTag_MCS_IQ_STANZA_TAG: 286 | result = &firebase_api.IqStanza{} 287 | break 288 | case firebase_api.MCSTag_MCS_DATA_MESSAGE_STANZA_TAG: 289 | result = &firebase_api.DataMessageStanza{} 290 | break 291 | default: 292 | return nil, fmt.Errorf("unknown tag: %d", tag) 293 | } 294 | err = proto.Unmarshal(data, result) 295 | if err != nil { 296 | return nil, fmt.Errorf("proto.Unmarshal[%x]: %w", data, err) 297 | } 298 | 299 | c.streamId++ 300 | // fmt.Println("IO:IN:\n", spew.Sdump(result)) 301 | return result, nil 302 | } 303 | 304 | func (c *MTalkCon) writeMessage(tag firebase_api.MCSTag, message proto.Message) error { 305 | // fmt.Println("IO:OUT:\n", spew.Sdump(message)) 306 | protoBytes, err := proto.Marshal(message) 307 | if err != nil { 308 | return fmt.Errorf("proto.Marshal: %w", err) 309 | } 310 | err = c.writeByte(uint8(tag)) 311 | if err != nil { 312 | return fmt.Errorf("c.writeByte[tag]: %w", err) 313 | } 314 | err = c.writeVarInt(len(protoBytes)) 315 | if err != nil { 316 | return fmt.Errorf("c.writeVarInt: %w", err) 317 | } 318 | err = c.writeBytes(protoBytes) 319 | if err != nil { 320 | return fmt.Errorf("c.writeByte[protobytes]: %w", err) 321 | } 322 | return nil 323 | } 324 | 325 | func (c *MTalkCon) login() error { 326 | authSvc := firebase_api.LoginRequest_ANDROID_ID 327 | request := &firebase_api.LoginRequest{ 328 | Id: proto.String("gms-22.48.14-000"), 329 | Domain: proto.String("mcs.android.com"), 330 | User: proto.String(strconv.FormatInt(c.Device.CheckinAndroidID, 10)), 331 | Resource: proto.String(strconv.FormatInt(c.Device.CheckinAndroidID, 10)), 332 | AuthToken: proto.String(strconv.FormatUint(c.Device.CheckinSecurityToken, 10)), 333 | DeviceId: proto.String(fmt.Sprintf("android-%s", c.Device.Device.Id.ToHexString())), 334 | Setting: []*firebase_api.Setting{{ 335 | Name: proto.String("new_vc"), 336 | Value: proto.String("1"), 337 | }, { 338 | Name: proto.String("os_ver"), 339 | Value: proto.String(fmt.Sprintf("android-%d", c.Device.Device.Version)), 340 | }, { 341 | Name: proto.String("ERR"), 342 | Value: proto.String("20"), 343 | }, { 344 | Name: proto.String("CT"), 345 | Value: proto.String("8"), 346 | }, { 347 | Name: proto.String("CONOK"), 348 | Value: proto.String("3"), 349 | }, { 350 | Name: proto.String("u:f"), 351 | Value: proto.String("0"), 352 | }, { 353 | Name: proto.String("networkOn"), 354 | Value: proto.String("0"), 355 | }}, 356 | ReceivedPersistentId: []string{c.Device.MTalkLastPersistentId}, 357 | AdaptiveHeartbeat: proto.Bool(false), 358 | UseRmq2: proto.Bool(true), 359 | AuthService: &authSvc, 360 | NetworkType: proto.Int32(1), 361 | } 362 | return c.writeMessage(firebase_api.MCSTag_MCS_LOGIN_REQUEST_TAG, request) 363 | } 364 | 365 | func (c *MTalkCon) readVarInt() (int, error) { 366 | shift := uint(0) 367 | result := int64(0) 368 | for { 369 | b, err := c.readByte() 370 | if err != nil { 371 | return 0, fmt.Errorf("c.readByte: %w", err) 372 | } 373 | result |= int64(b&0x7f) << shift 374 | if (b & 0x80) != 0x80 { 375 | break 376 | } 377 | shift += 7 378 | } 379 | return int(result), nil 380 | } 381 | 382 | func (c *MTalkCon) writeVarInt(value int) error { 383 | for { 384 | if (value & ^0x7F) == 0 { 385 | err := c.writeByte(byte(value)) 386 | if err != nil { 387 | return fmt.Errorf("c.writeByte[0]: %w", err) 388 | } 389 | break 390 | } else { 391 | err := c.writeByte(byte((value & 0x7F) | 0x80)) 392 | if err != nil { 393 | return fmt.Errorf("c.writeByte: %w", err) 394 | } 395 | u := uint32(value) 396 | value = int(u >> 7) 397 | } 398 | } 399 | return nil 400 | } 401 | 402 | func (c *MTalkCon) readBytes(len int) ([]byte, error) { 403 | buf := make([]byte, len) 404 | _, err := io.ReadFull(c.RawConn, buf) 405 | if err != nil && !errors.Is(err, io.EOF) { 406 | err = fmt.Errorf("io.ReadFull: %w", err) 407 | } else { 408 | err = nil 409 | } 410 | // fmt.Println(fmt.Sprintf("%s\tIO:BYTESIN:%s", time.Now().Format(time.RFC3339), hex.EncodeToString(result))) 411 | return buf, err 412 | } 413 | 414 | func (c *MTalkCon) readByte() (byte, error) { 415 | buf, err := c.readBytes(1) 416 | if err != nil { 417 | return 0, err 418 | } 419 | if len(buf) != 1 { 420 | return 0, errors.New("no data read") 421 | } 422 | return buf[0], nil 423 | } 424 | 425 | func (c *MTalkCon) writeBytes(data []byte) error { 426 | // fmt.Println(fmt.Sprintf("%s\tIO:BYTESOUT:%s", time.Now().Format(time.RFC3339), hex.EncodeToString(data))) 427 | _, err := c.RawConn.Write(data) 428 | if err != nil { 429 | // return fmt.Errorf("c.IO.WriteMessage: %w", err) 430 | return fmt.Errorf("c.RawConn.Write: %w", err) 431 | } 432 | return nil 433 | } 434 | 435 | func (c *MTalkCon) writeByte(data byte) error { 436 | return c.writeBytes([]byte{data}) 437 | } 438 | 439 | func parseAppDataValue(value string) map[string]string { 440 | result := make(map[string]string) 441 | pairs := strings.Split(value, ";") 442 | for _, pair := range pairs { 443 | if pair == "" { 444 | continue 445 | } 446 | 447 | kv := strings.SplitN(pair, "=", 2) 448 | if len(kv) == 2 { 449 | key := kv[0] 450 | val := kv[1] 451 | result[key] = val 452 | } 453 | } 454 | return result 455 | } 456 | -------------------------------------------------------------------------------- /constants/constants.go: -------------------------------------------------------------------------------- 1 | package constants 2 | 3 | import ( 4 | "fmt" 5 | go_android_utils "github.com/BRUHItsABunny/go-android-utils" 6 | ) 7 | 8 | const ( 9 | protocol = "https://" 10 | host = protocol + "firebaseinstallations.googleapis.com" 11 | firebaseHost = protocol + "www.googleapis.com/identitytoolkit/v3/relyingparty/" 12 | 13 | endpointProjects = host + "/v1/projects/%s" 14 | 15 | EndpointInstallations = endpointProjects + "/installations" 16 | EndpointVerifyPassword = firebaseHost + "verifyPassword" 17 | EndpointSignUpNewUser = firebaseHost + "signupNewUser" 18 | EndpointSetAccountInto = firebaseHost + "setAccountInfo" 19 | EndpointRefreshSecureToken = "https://securetoken.googleapis.com/v1/token" 20 | EndpointAuth = "https://android.googleapis.com/auth" 21 | EndpointAndroidCheckin = "https://android.clients.google.com/checkin" 22 | EndpointAndroidRegister = "https://android.clients.google.com/c2dm/register3" 23 | EndpointIOSCheckin = "https://device-provisioning.googleapis.com/checkin" 24 | EndpointIOSRegister = "https://fcmtoken.googleapis.com/register" 25 | 26 | HeaderKeyFireBaseClient = "x-firebase-client" 27 | HeaderKeyClientVersion = "x-client-version" 28 | HeaderKeyFireBaseLogType = "x-firebase-log-type" 29 | HeaderKeyAndroidCert = "X-Android-Cert" 30 | HeaderKeyAndroidPackage = "X-Android-Package" 31 | HeaderKeyGoogAPIKey = "x-goog-api-key" 32 | HeaderKeyUserAgent = "User-Agent" 33 | 34 | HeaderKeyContentType = "Content-Type" 35 | HeaderKeyAccept = "Accept" 36 | HeaderKeyCacheControl = "Cache-Control" 37 | 38 | HeaderValueMIMEJSON = "application/json" 39 | HeaderValueClientVersion = "Android/Fallback/X20000001/FirebaseCore-Android" 40 | 41 | MTalkHost = "mtalk.google.com" 42 | MTalkPort = "5228" 43 | ) 44 | 45 | var ( 46 | HeaderValueFireBaseClient = fmt.Sprintf("kotlin/1.4.10 fire-analytics/19.0.0 android-target-sdk/30 android-min-sdk/24 fire-core/20.0.0 device-name/%s device-model/%s fire-android/%s fire-iid/21.0.1 android-installer/com.android.vending device-brand/%s fire-installations/17.0.0 android-platform/ fire-fcm/20.1.7_1p", 47 | go_android_utils.DeviceFormatKeyDevice, 48 | go_android_utils.DeviceFormatKeyDevice, 49 | go_android_utils.DeviceFormatKeyAndroidSDKLevel, 50 | go_android_utils.DeviceFormatKeyManufacturer, 51 | ) 52 | ) 53 | -------------------------------------------------------------------------------- /example.env: -------------------------------------------------------------------------------- 1 | USE_PROXY="true" 2 | PROXY_URL="http://127.0.0.1:8888" -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/BRUHItsABunny/go-android-firebase 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.4 6 | 7 | replace github.com/xakep666/ecego => ../ecego 8 | 9 | require ( 10 | github.com/BRUHItsABunny/gOkHttp v0.3.7 11 | github.com/BRUHItsABunny/go-android-utils v0.0.27 12 | github.com/davecgh/go-spew v1.1.1 13 | github.com/google/uuid v1.6.0 14 | github.com/joho/godotenv v1.5.1 15 | github.com/xakep666/ecego v0.1.3 16 | go.uber.org/atomic v1.11.0 17 | google.golang.org/protobuf v1.36.5 18 | ) 19 | 20 | require ( 21 | github.com/google/go-cmp v0.5.9 // indirect 22 | golang.org/x/crypto v0.34.0 // indirect 23 | golang.org/x/net v0.33.0 // indirect 24 | golang.org/x/text v0.22.0 // indirect 25 | ) 26 | -------------------------------------------------------------------------------- /lib.go: -------------------------------------------------------------------------------- 1 | package firebase 2 | 3 | import ( 4 | "github.com/BRUHItsABunny/go-android-firebase/api" 5 | "github.com/BRUHItsABunny/go-android-firebase/client" 6 | "net/http" 7 | ) 8 | 9 | func NewFirebaseClient(hClient *http.Client, device *firebase_api.FirebaseDevice) (*firebase_client.FireBaseClient, error) { 10 | return firebase_client.NewFirebaseClient(hClient, device) 11 | } 12 | 13 | func RandomAppFID() string { 14 | result, _ := firebase_api.RandomAppFID() 15 | return result 16 | } 17 | -------------------------------------------------------------------------------- /lib_test.go: -------------------------------------------------------------------------------- 1 | package firebase 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/base64" 7 | "encoding/hex" 8 | "encoding/json" 9 | "errors" 10 | "fmt" 11 | gokhttp "github.com/BRUHItsABunny/gOkHttp" 12 | "github.com/BRUHItsABunny/gOkHttp/requests" 13 | "github.com/BRUHItsABunny/gOkHttp/responses" 14 | "github.com/BRUHItsABunny/go-android-firebase/api" 15 | andutils "github.com/BRUHItsABunny/go-android-utils" 16 | "github.com/davecgh/go-spew/spew" 17 | "github.com/google/uuid" 18 | "github.com/joho/godotenv" 19 | "google.golang.org/protobuf/proto" 20 | "io" 21 | "log" 22 | "net/http" 23 | "net/url" 24 | "os" 25 | "strings" 26 | "testing" 27 | "time" 28 | ) 29 | 30 | type FakeMTalk struct { 31 | buff *bytes.Buffer 32 | } 33 | 34 | func (c *FakeMTalk) readBytes(len int) ([]byte, error) { 35 | buf := make([]byte, len) 36 | var result []byte 37 | read, err := c.buff.Read(buf) 38 | if err != nil && !errors.Is(err, io.EOF) { 39 | err = fmt.Errorf(" c.buff.Read: %w", err) 40 | } else { 41 | err = nil 42 | } 43 | result = buf[:read] 44 | // fmt.Println(fmt.Sprintf("%s\tIO:BYTESIN:%s", time.Now().Format(time.RFC3339), hex.EncodeToString(result))) 45 | return result, err 46 | } 47 | 48 | func (c *FakeMTalk) readByte() (byte, error) { 49 | buf, err := c.readBytes(1) 50 | if err != nil { 51 | return 0, err 52 | } 53 | if len(buf) != 1 { 54 | return 0, errors.New("no data read") 55 | } 56 | return buf[0], nil 57 | } 58 | 59 | func (c *FakeMTalk) readVarInt() (int, error) { 60 | shift := uint(0) 61 | result := int64(0) 62 | for { 63 | b, err := c.readByte() 64 | if err != nil { 65 | return 0, fmt.Errorf("c.readByte: %w", err) 66 | } 67 | result |= int64(b&0x7f) << shift 68 | if (b & 0x80) != 0x80 { 69 | break 70 | } 71 | shift += 7 72 | } 73 | return int(result), nil 74 | } 75 | 76 | func NewFakeMTalk(fileName string) (*FakeMTalk, error) { 77 | fileBody, err := os.ReadFile(fileName) 78 | if err != nil { 79 | return nil, err 80 | } 81 | return &FakeMTalk{ 82 | buff: bytes.NewBuffer(fileBody), 83 | }, nil 84 | } 85 | 86 | func TestDecodeItem(t *testing.T) { 87 | c, err := NewFakeMTalk("_resources/samples/item.bin") 88 | if err != nil { 89 | log.Fatal(err) 90 | } 91 | tag, err := c.readByte() 92 | if err != nil { 93 | t.Fatal(fmt.Errorf("c.readByte: %w", err)) 94 | } 95 | length, err := c.readVarInt() 96 | if err != nil { 97 | t.Fatal(fmt.Errorf("c.readVarInt: %w", err)) 98 | } 99 | data, err := c.readBytes(length) 100 | if err != nil { 101 | t.Fatal(fmt.Errorf("c.readBytes data: %w", err)) 102 | } 103 | 104 | fmt.Println(tag, length, string(data)) 105 | fmt.Println(hex.EncodeToString(data)) 106 | 107 | var result proto.Message 108 | switch firebase_api.MCSTag(int(tag)) { 109 | case firebase_api.MCSTag_MCS_HEARTBEAT_PING_TAG: 110 | result = &firebase_api.HeartbeatPing{} 111 | break 112 | case firebase_api.MCSTag_MCS_HEARTBEAT_ACK_TAG: 113 | result = &firebase_api.HeartbeatAck{} 114 | break 115 | case firebase_api.MCSTag_MCS_LOGIN_REQUEST_TAG: 116 | result = &firebase_api.LoginRequest{} 117 | break 118 | case firebase_api.MCSTag_MCS_LOGIN_RESPONSE_TAG: 119 | result = &firebase_api.LoginResponse{} 120 | break 121 | case firebase_api.MCSTag_MCS_CLOSE_TAG: 122 | result = &firebase_api.Close{} 123 | break 124 | case firebase_api.MCSTag_MCS_IQ_STANZA_TAG: 125 | result = &firebase_api.IqStanza{} 126 | break 127 | case firebase_api.MCSTag_MCS_DATA_MESSAGE_STANZA_TAG: 128 | result = &firebase_api.DataMessageStanza{} 129 | break 130 | default: 131 | t.Fatal(fmt.Errorf("unknown tag: %d", tag)) 132 | } 133 | err = proto.Unmarshal(data, result) 134 | if err != nil { 135 | t.Fatal(fmt.Errorf("proto.Unmarshal[%x]: %w", data, err)) 136 | } 137 | 138 | fmt.Println(spew.Sdump(result)) 139 | // This succeeds so I know something is wrong in the registration/sending push notification part 140 | } 141 | 142 | func TestAuthLogin(t *testing.T) { 143 | err := godotenv.Load(".env") 144 | hClient, err := gokhttp.TestHTTPClient() 145 | if err != nil { 146 | t.Error(err) 147 | panic(err) 148 | } 149 | 150 | device := &firebase_api.FirebaseDevice{ 151 | Device: andutils.GetRandomDevice(), 152 | } 153 | appData := &firebase_api.FirebaseAppData{ 154 | PackageID: os.Getenv("AUTH_LOGIN_PACKAGE_ID"), 155 | PackageCertificate: os.Getenv("AUTH_LOGIN_PACKAGE_CERTIFICATE"), 156 | GoogleAPIKey: os.Getenv("AUTH_LOGIN_GOOGLE_API_KEY"), 157 | FirebaseProjectID: os.Getenv("AUTH_LOGIN_FIREBASE_PROJECT_ID"), 158 | } 159 | 160 | values := url.Values{ 161 | "add_account": {"1"}, 162 | "get_accountid": {"1"}, 163 | "google_play_services_version": {"220217000"}, 164 | "ACCESS_TOKEN": {"1"}, 165 | "operatorCountry": {"us"}, 166 | "service": {"ac2dm"}, 167 | } 168 | 169 | ctx := context.Background() 170 | client, err := NewFirebaseClient(hClient, device) 171 | if err != nil { 172 | t.Fatal(err) 173 | } 174 | 175 | resp, err := client.Auth(ctx, appData, values, os.Getenv("AUTH_LOGIN_EMAIL"), os.Getenv("AUTH_LOGIN_OAUTH_TOKEN")) 176 | if err == nil { 177 | fmt.Println(spew.Sdump(resp)) 178 | } else { 179 | fmt.Println(err) 180 | } 181 | } 182 | 183 | func TestAuthOAUTH(t *testing.T) { 184 | err := godotenv.Load(".env") 185 | hClient, err := gokhttp.TestHTTPClient() 186 | if err != nil { 187 | t.Error(err) 188 | panic(err) 189 | } 190 | device := &firebase_api.FirebaseDevice{ 191 | Device: andutils.GetRandomDevice(), 192 | } 193 | appData := &firebase_api.FirebaseAppData{ 194 | PackageID: os.Getenv("AUTH_OAUTH_PACKAGE_ID"), 195 | PackageCertificate: os.Getenv("AUTH_OAUTH_PACKAGE_CERTIFICATE"), 196 | GoogleAPIKey: os.Getenv("AUTH_OAUTH_GOOGLE_API_KEY"), 197 | FirebaseProjectID: os.Getenv("AUTH_OAUTH_FIREBASE_PROJECT_ID"), 198 | } 199 | 200 | values := url.Values{ 201 | "add_account": {"1"}, 202 | "get_accountid": {"1"}, 203 | "google_play_services_version": {"220217000"}, 204 | "ACCESS_TOKEN": {"1"}, 205 | "operatorCountry": {"us"}, 206 | "it_caveat_types": {"1"}, 207 | "oauth2_foreground": {"1"}, 208 | "has_permission": {"1"}, 209 | "token_request_options": {"CAA4AVAB"}, 210 | "check_email": {"1"}, 211 | "service": {"oauth2:https://www.googleapis.com/auth/accounts.reauth https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/identity.lateimpersonation https://www.googleapis.com/auth/assistant-sdk-prototype"}, 212 | "system_partition": {"1"}, 213 | } 214 | 215 | ctx := context.Background() 216 | client, err := NewFirebaseClient(hClient, device) 217 | if err != nil { 218 | t.Fatal(err) 219 | } 220 | 221 | resp, err := client.Auth(ctx, appData, values, os.Getenv("AUTH_OAUTH_EMAIL"), os.Getenv("AUTH_OAUTH_MASTER_TOKEN")) 222 | if err == nil { 223 | fmt.Println(spew.Sdump(resp)) 224 | } else { 225 | fmt.Println(err) 226 | } 227 | } 228 | 229 | func TestNotify(t *testing.T) { 230 | err := godotenv.Load(".env") 231 | hClient, err := gokhttp.TestHTTPClient() 232 | if err != nil { 233 | t.Error(err) 234 | panic(err) 235 | } 236 | device := &firebase_api.FirebaseDevice{ 237 | Device: andutils.GetRandomDevice(), 238 | } 239 | appData := &firebase_api.FirebaseAppData{ 240 | PackageID: os.Getenv("NOTIFY_PACKAGE_ID"), 241 | PackageCertificate: os.Getenv("NOTIFY_PACKAGE_CERTIFICATE"), 242 | GoogleAPIKey: os.Getenv("NOTIFY_GOOGLE_API_KEY"), 243 | FirebaseProjectID: os.Getenv("NOTIFY_FIREBASE_PROJECT_ID"), 244 | } 245 | 246 | ctx := context.Background() 247 | client, err := NewFirebaseClient(hClient, device) 248 | if err != nil { 249 | t.Fatal(err) 250 | } 251 | 252 | resp, err := client.NotifyInstallation(ctx, appData) 253 | if err == nil { 254 | fmt.Println(spew.Sdump(resp)) 255 | } else { 256 | fmt.Println(err) 257 | } 258 | } 259 | 260 | func TestVerifyPassword(t *testing.T) { 261 | err := godotenv.Load(".env") 262 | hClient, err := gokhttp.TestHTTPClient() 263 | if err != nil { 264 | t.Error(err) 265 | panic(err) 266 | } 267 | device := &firebase_api.FirebaseDevice{ 268 | Device: andutils.GetRandomDevice(), 269 | } 270 | appData := &firebase_api.FirebaseAppData{ 271 | PackageID: os.Getenv("VERIFY_PASSWORD_PACKAGE_ID"), 272 | PackageCertificate: os.Getenv("VERIFY_PASSWORD_PACKAGE_CERTIFICATE"), 273 | GoogleAPIKey: os.Getenv("VERIFY_PASSWORD_GOOGLE_API_KEY"), 274 | FirebaseProjectID: os.Getenv("VERIFY_PASSWORD_FIREBASE_PROJECT_ID"), 275 | } 276 | var ( 277 | email = os.Getenv("VERIFY_PASSWORD_USERNAME") 278 | password = os.Getenv("VERIFY_PASSWORD_PASSWORD") 279 | ) 280 | ctx := context.Background() 281 | client, err := NewFirebaseClient(hClient, device) 282 | if err != nil { 283 | t.Fatal(err) 284 | } 285 | 286 | req := &firebase_api.VerifyPasswordRequestBody{ 287 | Email: email, 288 | Password: password, 289 | ReturnSecureToken: true, 290 | } 291 | resp, err := client.VerifyPassword(ctx, req, appData) 292 | if err == nil { 293 | fmt.Println(spew.Sdump(resp)) 294 | } else { 295 | fmt.Println(err) 296 | } 297 | } 298 | 299 | func TestRegister3(t *testing.T) { 300 | ctx := context.Background() 301 | device := andutils.GetRandomDevice() 302 | appData := &firebase_api.FirebaseAppData{ 303 | PackageID: "org.wikipedia", 304 | PackageCertificate: "D21A6A91AA75C937C4253770A8F7025C6C2A8319", 305 | GoogleAPIKey: "AIzaSyC7m9NhFXHiUPryquw7PecqFO0d9YPrVNE", 306 | FirebaseProjectID: "pushnotifications-73c5e", 307 | GMPAppID: "1:296120793014:android:34d2ba8d355ca9259a7317", 308 | NotificationSenderID: "296120793014", 309 | AppVersion: "2.7.50394-r-2022-02-10", 310 | AppVersionWithBuild: "50394", 311 | AuthVersion: "FIS_v2", 312 | SdkVersion: "a:17.0.0", 313 | AppNameHash: "R1dAH9Ui7M-ynoznwBdw01tLxhI", 314 | } 315 | fDevice := &firebase_api.FirebaseDevice{ 316 | Device: device, 317 | CheckinAndroidID: 0, 318 | CheckinSecurityToken: 0, 319 | GmsVersion: "214815028", 320 | FirebaseClientVersion: "fcm-22.0.0", 321 | } 322 | 323 | err := godotenv.Load(".env") 324 | hClient, err := gokhttp.TestHTTPClient() 325 | if err != nil { 326 | t.Error(err) 327 | } 328 | 329 | fClient, err := NewFirebaseClient(hClient, fDevice) 330 | if err != nil { 331 | t.Fatal(err) 332 | } 333 | authResult, err := fClient.NotifyInstallation(ctx, appData) 334 | if err != nil { 335 | t.Error(err) 336 | } 337 | fmt.Println(spew.Sdump(authResult)) 338 | 339 | checkinResult, err := fClient.Checkin(ctx, appData, "", "") 340 | if err != nil { 341 | t.Error(err) 342 | } 343 | fmt.Println(fmt.Sprintf("AndroidID (checkin): %d\nSecurityToken: %d", checkinResult.AndroidId, checkinResult.SecurityToken)) 344 | 345 | result, err := fClient.C2DMRegisterAndroid(ctx, appData) 346 | if err != nil { 347 | t.Error(err) 348 | } 349 | 350 | fmt.Println("notificationToken: \n", result) 351 | 352 | // Check if fDevice was updated with the new information returned by the api calls 353 | prettyBytes, err := json.MarshalIndent(fDevice, "", " ") 354 | if err != nil { 355 | t.Error(err) 356 | } 357 | fmt.Println(string(prettyBytes)) 358 | } 359 | 360 | func TestNativePushNotifications(t *testing.T) { 361 | ctx := context.Background() 362 | device := andutils.GetRandomDevice() 363 | appData := &firebase_api.FirebaseAppData{ 364 | PackageID: "fr.smarquis.fcm", 365 | PackageCertificate: "FC674E2E5582B7BEA69EE5CA921FCEFAD2918452", 366 | GoogleAPIKey: " AIzaSyDBHR45cWSsnJw-7inTYFDtK39-0TpjlhA", 367 | FirebaseProjectID: "fir-cloudmessaging-4e2cd", 368 | GMPAppID: "1:322141800886:android:7b41fd8ce1e97722", 369 | NotificationSenderID: "322141800886", 370 | AppVersion: "1.9.0", 371 | AppVersionWithBuild: "1090000", 372 | AuthVersion: "FIS_v2", 373 | SdkVersion: "a:17.1.3", 374 | AppNameHash: "R1dAH9Ui7M-ynoznwBdw01tLxhI", 375 | } 376 | fDevice := &firebase_api.FirebaseDevice{ 377 | Device: device, 378 | CheckinAndroidID: 0, 379 | CheckinSecurityToken: 0, 380 | GmsVersion: "241718022", 381 | FirebaseClientVersion: "fcm-23.1.2", 382 | } 383 | 384 | err := godotenv.Load(".env") 385 | hClient, err := gokhttp.TestHTTPClient() 386 | if err != nil { 387 | t.Error(err) 388 | } 389 | 390 | fClient, err := NewFirebaseClient(hClient, fDevice) 391 | if err != nil { 392 | t.Fatal(err) 393 | } 394 | _, err = fClient.NotifyInstallation(ctx, appData) 395 | if err != nil { 396 | t.Error(err) 397 | } 398 | 399 | time.Sleep(time.Second * 5) 400 | 401 | checkinResult, err := fClient.Checkin(ctx, appData, "", "") 402 | if err != nil { 403 | t.Error(err) 404 | } 405 | fmt.Println(fmt.Sprintf("AndroidID (checkin): %d\nSecurityToken: %d", checkinResult.AndroidId, checkinResult.SecurityToken)) 406 | time.Sleep(time.Second * 5) 407 | 408 | result, err := fClient.C2DMRegisterAndroid(ctx, appData) 409 | if err != nil { 410 | t.Error(err) 411 | } 412 | 413 | fmt.Println("notificationToken: \n", result) 414 | 415 | time.Sleep(time.Second * 10) // it will error out if we don't wait, there is a latency between checkin credentials being registered with gcm/fcm and being registered with mtalk 416 | 417 | err = fClient.MTalk.Connect() 418 | if err != nil { 419 | t.Error(err) 420 | } 421 | 422 | time.Sleep(time.Second * 3) 423 | resultChan := make(chan *firebase_api.DataMessageStanza) 424 | fClient.MTalk.OnNotification = func(notification *firebase_api.DataMessageStanza) { 425 | resultChan <- notification 426 | } 427 | pre := time.Now() 428 | err = sendPushNotificationNative(fDevice, hClient, result) 429 | if err != nil { 430 | t.Error(err) 431 | } 432 | fmt.Println("Waiting for message") 433 | msg := <-resultChan 434 | latency := time.Now().Sub(pre) 435 | fmt.Println(spew.Sdump(msg)) 436 | fmt.Println("Latency: ", latency) 437 | } 438 | 439 | func TestWebPushNotifications(t *testing.T) { 440 | ctx := context.Background() 441 | device := andutils.GetRandomDevice() 442 | appData := &firebase_api.FirebaseAppData{ 443 | PackageID: "com.brave.browser", 444 | PackageCertificate: "4b5d0914b118f51f30634a1523f96e020ab24fd2", 445 | AppVersion: "1.75.180", 446 | AppVersionWithBuild: "427518024", 447 | } 448 | fDevice := &firebase_api.FirebaseDevice{ 449 | Device: device, 450 | CheckinAndroidID: 0, 451 | CheckinSecurityToken: 0, 452 | GmsVersion: "250632029", 453 | FirebaseClientVersion: "fcm-22.0.0", 454 | } 455 | 456 | err := godotenv.Load(".env") 457 | hClient, err := gokhttp.TestHTTPClient() 458 | if err != nil { 459 | t.Error(err) 460 | } 461 | 462 | fClient, err := NewFirebaseClient(hClient, fDevice) 463 | if err != nil { 464 | t.Fatal(err) 465 | } 466 | 467 | checkinResult, err := fClient.Checkin(ctx, appData, "", "") 468 | if err != nil { 469 | t.Error(err) 470 | } 471 | fmt.Println(fmt.Sprintf("AndroidID (checkin): %d\nSecurityToken: %d", checkinResult.AndroidId, checkinResult.SecurityToken)) 472 | time.Sleep(time.Second * 5) 473 | 474 | sender := getNotificationDataWeb() 475 | uuidStr := strings.ToUpper(uuid.New().String()) 476 | subType := "https://push.foo/#" + uuidStr[:len(uuidStr)-3] 477 | appid := "f1pdRYedASE" // TODO: IDK where this one comes from 478 | 479 | result, err := fClient.C2DMRegisterWeb(ctx, appData, sender, subType, appid) 480 | if err != nil { 481 | t.Error(err) 482 | } 483 | 484 | fmt.Println("notificationToken: \n", result) 485 | 486 | time.Sleep(time.Second * 10) // it will error out if we don't wait, there is a latency between checkin credentials being registered with gcm/fcm and being registered with mtalk 487 | 488 | err = fClient.MTalk.Connect() 489 | if err != nil { 490 | t.Error(err) 491 | } 492 | 493 | time.Sleep(time.Second * 3) 494 | resultChan := make(chan *firebase_api.DataMessageStanza) 495 | fClient.MTalk.OnNotification = func(notification *firebase_api.DataMessageStanza) { 496 | resultChan <- notification 497 | } 498 | pre := time.Now() 499 | err = sendNotificationWeb(hClient, result, fDevice.MTalkPublicKey, fDevice.MTalkAuthSecret) 500 | if err != nil { 501 | t.Error(err) 502 | } 503 | fmt.Println("Waiting for message") 504 | msg := <-resultChan 505 | latency := time.Now().Sub(pre) 506 | fmt.Println(spew.Sdump(msg)) 507 | fmt.Println("Latency: ", latency) 508 | } 509 | 510 | func TestRandomAppFID(t *testing.T) { 511 | fmt.Println(RandomAppFID()) 512 | } 513 | 514 | func TestBits(t *testing.T) { 515 | fmt.Println(firebase_api.GetLeastMostSignificantBits("a316b044-0157-1000-efe6-40fc5d2f0036")) 516 | } 517 | 518 | func TestConvert(t *testing.T) { 519 | fmt.Println(base64.StdEncoding.DecodeString("cA==")) 520 | } 521 | 522 | func sendPushNotificationNative(fDevice *firebase_api.FirebaseDevice, client *http.Client, token string) error { 523 | headerOpt := gokhttp_requests.NewHeaderOption(http.Header{}) 524 | 525 | body := strings.ReplaceAll("{\"data\":{\"to\":\"$TOKEN\",\"ttl\":60,\"priority\":\"high\",\"data\":{\"ping\":{}}}}", "$TOKEN", token) 526 | req, err := gokhttp_requests.MakePOSTRequest(context.Background(), "https://us-central1-fir-cloudmessaging-4e2cd.cloudfunctions.net/send", headerOpt, gokhttp_requests.NewPOSTJSONOption([]byte(body), false)) 527 | if err != nil { 528 | return err 529 | } 530 | 531 | resp, err := client.Do(req) 532 | if err != nil { 533 | return err 534 | } 535 | 536 | respText, err := gokhttp_responses.ResponseText(resp) 537 | if err != nil { 538 | return err 539 | } 540 | fmt.Println(respText) 541 | return nil 542 | } 543 | 544 | func sendNotificationWeb(client *http.Client, token, publicKey, authNonce string) error { 545 | headerOpt := gokhttp_requests.NewHeaderOption(http.Header{}) 546 | 547 | body := strings.ReplaceAll("{\"pushSubscription\":{\"endpoint\":\"https://fcm.googleapis.com/fcm/send/$TOKEN\",\"expirationTime\":null,\"keys\":{\"p256dh\":\"$PUBLIC_KEY\",\"auth\":\"$AUTH_NONCE\"}},\"notification\":{\"title\":\"Push.Foo Notification Title\",\"actions\":[{\"action\":\"open_project_repo\",\"title\":\"Show source code\"},{\"action\":\"open_author_twitter\",\"title\":\"Author on Twitter\"},{\"action\":\"open_author_linkedin\",\"title\":\"Author on LinkedIn\"},{\"action\":\"open_url\",\"title\":\"Open custom URL\"}],\"body\":\"Test notification body\",\"dir\":\"auto\",\"image\":\"https://push.foo/images/social.png\",\"icon\":\"https://push.foo/images/logo.jpg\",\"badge\":\"https://push.foo/images/logo-mask.png\",\"lang\":\"en-US\",\"renotify\":false,\"requireInteraction\":true,\"silent\":false,\"tag\":\"Custom tag\",\"timestamp\":1740333526775,\"data\":{\"dateOfArrival\":1740333526775,\"updateInAppCounter\":true,\"updateIconBadgeCounter\":true,\"author\":{\"name\":\"Maxim Salnikov\",\"github\":\"https://github.com/webmaxru\",\"twitter\":\"https://twitter.com/webmaxru\",\"linkedin\":\"https://www.linkedin.com/in/webmax/\"},\"project\":{\"github\":\"https://github.com/webmaxru/push.foo\"},\"action\":{\"url\":\"https://push.foo\"}}}}", "$TOKEN", token) 548 | body = strings.ReplaceAll(body, "$PUBLIC_KEY", publicKey) 549 | body = strings.ReplaceAll(body, "$AUTH_NONCE", authNonce) 550 | 551 | req, err := gokhttp_requests.MakePOSTRequest(context.Background(), "https://push.foo/api/quick-notification", headerOpt, gokhttp_requests.NewPOSTJSONOption([]byte(body), false)) 552 | if err != nil { 553 | return err 554 | } 555 | 556 | resp, err := client.Do(req) 557 | if err != nil { 558 | return err 559 | } 560 | 561 | respText, err := gokhttp_responses.ResponseText(resp) 562 | if err != nil { 563 | return err 564 | } 565 | fmt.Println(respText) 566 | return nil 567 | } 568 | 569 | func getNotificationDataWeb() string { 570 | // Use https://push.foo 571 | // Return publicKey (sender) 572 | return "BDweuGCGNzjleeyQYPvtFLEbMG4BX9rc_M9Abtx16NvaR_Jpo5i08WAJUll2Hn6ZiErbSjkzxWdpKjus_qO2cMw" 573 | } 574 | 575 | // TODO: Write unittests with this: 576 | // https://tests.peter.sh/push-message-generator/ 577 | // https://github.com/beverloo/peter.sh/tree/master/tests 578 | --------------------------------------------------------------------------------