Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload to Google Cloud Storage using service account from iOS app

So I've been trying to upload audio / video files from iOS app to Google Cloud Server. I want the user doesn't have to login to their google account before uploading. Currently, my working solutions is to make the bucket on the server "open", which is basically available for every person on the Internet to read/write the bucket. I set API key to my GTLServiceStorage object on iOS:

_serviceStorage.additionalHTTPHeaders = HTTP_HEADERS;
_serviceStorage.APIKey = kCloudBackendAPIKey;

This way, the user from within the app should be able to upload without login.

Now, I want the bucket to be private so only user from authorized app could access it.

On Android, I'm able to do it using the certificate I generate from the server and implement it to Android project files through the example from Google Documentation page. (Using service account id & PKCS12 files). The code on Android to set the credential is like this :

KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(getResources().openRawResource(R.raw.secret), MY_PASSWD.toCharArray());

PrivateKey key = (PrivateKey) keystore.getKey("privatekey", MY_PASSWD.toCharArray());

GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_ID)
.setServiceAccountScopes(scopes)
.setServiceAccountPrivateKey(key)
.build();

storage = new Storage.Builder(httpTransport, jsonFactory, credential)
          .setApplicationName(APP_NAME).build();

// --- continue upload using storage

However, for now I can't seem find a way to implement the same mechanism into my iOS app. Is there any way I could use google service account id to upload files within the iOS app so the user doesn't have to login to their goolge account first ?

like image 347
adipurnama Avatar asked Nov 11 '22 08:11

adipurnama


1 Answers

Keeping your private key in the application is not safe for production and is not the correct way to do this. Also, you can't use the same trick with IOS.

The solution is to create a public api key (https://console.developers.google.com -> project -> credentials -> Create new key (under public api access) -> Android/IOS key.

This should be safe enough because potentially the key is tied to the sha-1 and name of your android application. I should note though that restricting this has not worked for me yet, so in the mean time I left the field empty which makes it "Any application allowed" - I will update this answer when I find out how to do this properly.

Here is how I did this in android:

HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = AndroidJsonFactory.getDefaultInstance();

mStorage = new Storage.Builder(httpTransport, jsonFactory, null)
            .setApplicationName(PROJECT_ID)
            .build();
...
...
mStorage.objects()
                .get(BUCKET_NAME, fileName)
                .setKey(API_KEY)
                .setAlt("media")
                .executeAndDownloadTo(stream);

If you by any chance find out how to restrict the usage to a single application I would love to hear the answer as well :)

good luck

like image 89
maxandron Avatar answered Nov 15 '22 04:11

maxandron