View Javadoc
1   /*
2    * Copyright 2014 Google Inc. All rights reserved.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.simpligility.maven.plugins.android.common;
18  
19  import com.google.api.client.auth.oauth2.Credential;
20  import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
21  import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
22  import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
23  import com.google.api.client.http.HttpTransport;
24  import com.google.api.client.json.JsonFactory;
25  import com.google.api.client.json.jackson2.JacksonFactory;
26  import com.google.api.client.repackaged.com.google.common.base.Preconditions;
27  import com.google.api.client.repackaged.com.google.common.base.Strings;
28  import com.google.api.services.androidpublisher.AndroidPublisher;
29  import com.google.api.services.androidpublisher.AndroidPublisherScopes;
30  
31  import java.io.File;
32  import java.io.IOException;
33  import java.security.GeneralSecurityException;
34  import java.util.Collections;
35  
36  import javax.annotation.Nullable;
37  
38  import org.apache.commons.logging.Log;
39  import org.apache.commons.logging.LogFactory;
40  
41  /**
42   * Helper class to initialize the publisher APIs client library.
43   * <p>
44   * Before making any calls to the API through the client library you need to
45   * call the {@link AndroidPublisherHelper#init(String)} method. This will run
46   * all precondition checks for for client id and secret setup properly in
47   * resources/client_secrets.json and authorize this client against the API.
48   * </p>
49   */
50  public class AndroidPublisherHelper
51  {
52  
53      private static final Log LOG = LogFactory.getLog( AndroidPublisherHelper.class );
54  
55      public static final String MIME_TYPE_APK = "application/vnd.android.package-archive";
56  
57      public static final String MIME_TYPE_IMAGE = "image/*";
58  
59      /** Path to the private key file (only used for Service Account auth). */
60      private static final String SRC_RESOURCES_KEY_P12 = "resources/key.p12";
61  
62      /**
63       * Path to the client secrets file (only used for Installed Application
64       * auth).
65       */
66      private static final String RESOURCES_CLIENT_SECRETS_JSON = "/resources/client_secrets.json";
67  
68      /**
69       * Directory to store user credentials (only for Installed Application
70       * auth).
71       */
72      private static final String DATA_STORE_SYSTEM_PROPERTY = "user.home";
73      private static final String DATA_STORE_FILE = ".store/android_publisher_api";
74      private static final File DATA_STORE_DIR =
75              new File( System.getProperty( DATA_STORE_SYSTEM_PROPERTY ), DATA_STORE_FILE );
76  
77      /** Global instance of the JSON factory. */
78      private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
79  
80      /** Global instance of the HTTP transport. */
81      private static HttpTransport httpTransport;
82  
83      /** Installed application user ID. */
84      private static final String INST_APP_USER_ID = "user";
85  
86      private static Credential authorizeWithServiceAccount( String serviceAccountEmail )
87              throws GeneralSecurityException, IOException
88      {
89          LOG.info( String.format( "Authorizing using Service Account: %s", serviceAccountEmail ) );
90  
91          return authorizeWithServiceAccount( serviceAccountEmail, null );
92      }
93  
94      private static Credential authorizeWithServiceAccount( String serviceAccountEmail, File pk12File )
95              throws GeneralSecurityException, IOException
96      {
97          LOG.info( String.format( "Authorizing using Service Account: %s", serviceAccountEmail ) );
98  
99          // Build service account credential.
100         GoogleCredential credential = new GoogleCredential.Builder()
101                 .setTransport( httpTransport )
102                 .setJsonFactory( JSON_FACTORY )
103                 .setServiceAccountId( serviceAccountEmail )
104                 .setServiceAccountScopes( Collections.singleton( AndroidPublisherScopes.ANDROIDPUBLISHER ) )
105                 .setServiceAccountPrivateKeyFromP12File( pk12File == null ? new File( SRC_RESOURCES_KEY_P12 )
106                         : pk12File )
107                 .build();
108         return credential;
109     }
110 
111     /**
112      * Ensure the client secrets file has been filled out.
113      *
114      * @param clientSecrets the GoogleClientSecrets containing data from the
115      *            file
116      */
117     private static void checkClientSecretsFile( GoogleClientSecrets clientSecrets )
118     {
119         if ( clientSecrets.getDetails().getClientId().startsWith( "[[INSERT" )
120                 || clientSecrets.getDetails().getClientSecret().startsWith( "[[INSERT" ) )
121         {
122             LOG.error( "Enter Client ID and Secret from "
123                     + "APIs console into resources/client_secrets.json." );
124             System.exit( 1 );
125         }
126     }
127 
128     /**
129      * Performs all necessary setup steps for running requests against the API
130      * using the Installed Application auth method.
131      *
132      * @param applicationName the name of the application: com.example.app
133      * @return the {@Link AndroidPublisher} service
134      */
135     public static AndroidPublisher init( String applicationName ) throws Exception
136     {
137         return init( applicationName, null );
138     }
139 
140     /**
141      * Performs all necessary setup steps for running requests against the API.
142      *
143      * @param applicationName the name of the application: com.example.app
144      * @param serviceAccountEmail the Service Account Email (empty if using
145      *            installed application)
146      * @return the {@Link AndroidPublisher} service
147      * @throws GeneralSecurityException
148      * @throws IOException
149      */
150     public static AndroidPublisher init( String applicationName,
151             @Nullable String serviceAccountEmail ) throws IOException, GeneralSecurityException
152     {
153         Preconditions.checkArgument( !Strings.isNullOrEmpty( applicationName ),
154                 "applicationName cannot be null or empty!" );
155 
156         // Authorization.
157         newTrustedTransport();
158         Credential credential;
159         credential = authorizeWithServiceAccount( serviceAccountEmail );
160 
161         // Set up and return API client.
162         return new AndroidPublisher.Builder(
163                 httpTransport, JSON_FACTORY, credential ).setApplicationName( applicationName )
164                 .build();
165     }
166 
167     /**
168      * Performs all necessary setup steps for running requests against the API.
169      *
170      * @param serviceAccountEmail the Service Account Email (empty if using
171      *            installed application)
172      * @return the {@Link AndroidPublisher} service
173      * @throws GeneralSecurityException
174      * @throws IOException
175      */
176     public static AndroidPublisher init( String applicationName, String serviceAccountEmail, File pk12File )
177             throws IOException, GeneralSecurityException
178     {
179 
180         // Authorization.
181         newTrustedTransport();
182         Credential credential = authorizeWithServiceAccount( serviceAccountEmail, pk12File );
183 
184         // Set up and return API client.
185         return new AndroidPublisher.Builder( httpTransport, JSON_FACTORY, credential )
186                 .setApplicationName( applicationName )
187                 .build();
188     }
189 
190     private static void newTrustedTransport() throws GeneralSecurityException,
191             IOException
192     {
193         if ( null == httpTransport )
194         {
195             httpTransport = GoogleNetHttpTransport.newTrustedTransport();
196         }
197     }
198 
199 }