diff --git a/bitwarden-mobile.sln b/bitwarden-mobile.sln
index e493d47ef..2a5ca3e60 100644
--- a/bitwarden-mobile.sln
+++ b/bitwarden-mobile.sln
@@ -23,6 +23,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iOS.Test", "test\iOS.Test\i
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Android.Test", "test\Android.Test\Android.Test.csproj", "{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "store", "store", "{92470CBD-9047-4C3C-8EA3-D972D6622D84}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "google", "google", "{2E399654-26A2-46F6-B9CA-1B496A3F370A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Publisher", "store\google\Publisher\Publisher.csproj", "{428CACAB-CC26-4F41-9062-1E4A9BC82640}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@@ -411,6 +417,54 @@ Global
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.ActiveCfg = Release|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.Build.0 = Release|Any CPU
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE}.Release|x86.Deploy.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x64.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Ad-Hoc|x86.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|Any CPU.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|ARM.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|ARM.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhone.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhone.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x64.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x64.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x86.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.AppStore|x86.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|ARM.Build.0 = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x64.Build.0 = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Debug|x86.Build.0 = Debug|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|Any CPU.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|ARM.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|ARM.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhone.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x64.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x64.Build.0 = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x86.ActiveCfg = Release|Any CPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -424,5 +478,7 @@ Global
{B2538ADA-B605-4D6F-ACD2-62A409680F84} = {EC730FD9-F623-4B6C-B503-95CDCFBCF277}
{6702027A-F726-4149-863E-7CB924674B9A} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
{FA507A17-D4E3-46DF-ACD8-D7E6D7D4E3AE} = {0D790714-ECF8-4A83-BE4A-E9C84DD1BB5D}
+ {2E399654-26A2-46F6-B9CA-1B496A3F370A} = {92470CBD-9047-4C3C-8EA3-D972D6622D84}
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640} = {2E399654-26A2-46F6-B9CA-1B496A3F370A}
EndGlobalSection
EndGlobal
diff --git a/store/google/Publisher/App.config b/store/google/Publisher/App.config
new file mode 100644
index 000000000..1e1ff7e0f
--- /dev/null
+++ b/store/google/Publisher/App.config
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/store/google/Publisher/Program.cs b/store/google/Publisher/Program.cs
new file mode 100644
index 000000000..d58af0b67
--- /dev/null
+++ b/store/google/Publisher/Program.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Threading.Tasks;
+using Google.Apis.AndroidPublisher.v2;
+using Google.Apis.Services;
+using System.Collections.Generic;
+using Google.Apis.AndroidPublisher.v2.Data;
+using System.IO;
+
+namespace Bit.Publisher
+{
+ class Program
+ {
+ private const string Package = "com.x8bit.bitwarden";
+
+ private static string _apkFilePath;
+ private static string _apiKey;
+ private static EditsResource.TracksResource.UpdateRequest.TrackEnum _track;
+
+ static void Main(string[] args)
+ {
+ if(args.Length < 3)
+ {
+ throw new ArgumentException("Not enough arguments.");
+ }
+
+ try
+ {
+ _apiKey = args[0];
+ _apkFilePath = args[1];
+
+ var track = args[2].Substring(0, 1).ToLower();
+ if(args[2] == "a")
+ {
+ _track = EditsResource.TracksResource.UpdateRequest.TrackEnum.Alpha;
+ }
+ else if(args[2] == "b")
+ {
+ _track = EditsResource.TracksResource.UpdateRequest.TrackEnum.Beta;
+ }
+ else if(args[2] == "p")
+ {
+ _track = EditsResource.TracksResource.UpdateRequest.TrackEnum.Production;
+ }
+ else if(args[2] == "r")
+ {
+ _track = EditsResource.TracksResource.UpdateRequest.TrackEnum.Rollout;
+ }
+
+ new Program().Run().Wait();
+ }
+ catch(AggregateException ex)
+ {
+ foreach(var e in ex.InnerExceptions)
+ {
+ Console.WriteLine("ERROR: " + e.Message);
+ }
+ }
+ }
+
+ private async Task Run()
+ {
+ var service = new AndroidPublisherService(new BaseClientService.Initializer
+ {
+ ApplicationName = "appveyor",
+ ApiKey = _apiKey,
+ });
+
+ var editsRequest = new EditsResource.InsertRequest(
+ service,
+ null,
+ Package);
+ var edit = await editsRequest.ExecuteAsync();
+
+ Console.WriteLine("Created edit with id {0}.", edit.Id);
+
+ Apk apk = null;
+ var apkResource = new EditsResource.ApksResource(service);
+ using(var stream = new FileStream(_apkFilePath, FileMode.Open))
+ {
+ var uploadMedia = apkResource.Upload(
+ Package,
+ edit.Id,
+ stream,
+ "application/vnd.android.package-archive");
+ var progress = await uploadMedia.UploadAsync();
+ if(progress.Status == Google.Apis.Upload.UploadStatus.Completed)
+ {
+ apk = uploadMedia.ResponseBody;
+ }
+ else
+ {
+ throw new Exception("Upload failed.");
+ }
+ }
+
+ Console.WriteLine("Version code {0} has been uploaded.", apk.VersionCode);
+
+ var trackRequest = new EditsResource.TracksResource.UpdateRequest(
+ service,
+ new Track
+ {
+ VersionCodes = new List { apk.VersionCode }
+ },
+ Package,
+ edit.Id,
+ _track);
+ var updatedTrack = await trackRequest.ExecuteAsync();
+
+ Console.WriteLine("Track {0} has been updated.", updatedTrack.TrackValue);
+
+ var commitRequest = new EditsResource.CommitRequest(
+ service,
+ Package,
+ edit.Id);
+ var commitEdit = await commitRequest.ExecuteAsync();
+
+ Console.WriteLine("App edit with id {0} has been comitted.", commitEdit.Id);
+ }
+ }
+}
diff --git a/store/google/Publisher/Properties/AssemblyInfo.cs b/store/google/Publisher/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..b6743c348
--- /dev/null
+++ b/store/google/Publisher/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Publisher")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Publisher")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("428cacab-cc26-4f41-9062-1e4a9bc82640")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/store/google/Publisher/Publisher.csproj b/store/google/Publisher/Publisher.csproj
new file mode 100644
index 000000000..e2ef5f3fd
--- /dev/null
+++ b/store/google/Publisher/Publisher.csproj
@@ -0,0 +1,97 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {428CACAB-CC26-4F41-9062-1E4A9BC82640}
+ Exe
+ Properties
+ Bit.Publisher
+ Publisher
+ v4.6.1
+ 512
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\..\packages\Google.Apis.1.20.0\lib\net45\Google.Apis.dll
+ True
+
+
+ ..\..\..\packages\Google.Apis.AndroidPublisher.v2.1.20.0.735\lib\net45\Google.Apis.AndroidPublisher.v2.dll
+ True
+
+
+ ..\..\..\packages\Google.Apis.Auth.1.20.0\lib\net45\Google.Apis.Auth.dll
+ True
+
+
+ ..\..\..\packages\Google.Apis.Auth.1.20.0\lib\net45\Google.Apis.Auth.PlatformServices.dll
+ True
+
+
+ ..\..\..\packages\Google.Apis.Core.1.20.0\lib\net45\Google.Apis.Core.dll
+ True
+
+
+ ..\..\..\packages\Google.Apis.1.20.0\lib\net45\Google.Apis.PlatformServices.dll
+ True
+
+
+ ..\..\..\packages\log4net.2.0.7\lib\net45-full\log4net.dll
+ True
+
+
+ ..\..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+
+
+
+
+
+
+
+
+ ..\..\..\packages\Zlib.Portable.Signed.1.11.0\lib\portable-net4+sl5+wp8+win8+wpa81+MonoTouch+MonoAndroid\Zlib.Portable.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/store/google/Publisher/packages.config b/store/google/Publisher/packages.config
new file mode 100644
index 000000000..3ea07b84f
--- /dev/null
+++ b/store/google/Publisher/packages.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file