Skip to content

Commit 209a67f

Browse files
committed
8.3.3 beta release with google drive backup upload support (experimental)
1 parent 7967d0b commit 209a67f

File tree

5 files changed

+262
-18
lines changed

5 files changed

+262
-18
lines changed

pom.xml

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ AUTO-GENERATED FILE, CHANGES SHOULD BE DONE IN ./JPM.java or ./src/main/java/JPM
1111
<modelVersion>4.0.0</modelVersion>
1212
<groupId>com.osiris.autoplug.client</groupId>
1313
<artifactId>AutoPlug-Client</artifactId>
14-
<version>8.3.2</version>
14+
<version>8.3.3</version>
1515
<properties>
1616
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1717
<java.version>9</java.version>
18-
<version>8.3.2</version>
18+
<version>8.3.3</version>
1919
<main-class>com.osiris.autoplug.client.Main</main-class>
2020
<slf4j.version>2.0.13</slf4j.version>
2121
<name>AutoPlug-Client</name>
@@ -102,6 +102,42 @@ AUTO-GENERATED FILE, CHANGES SHOULD BE DONE IN ./JPM.java or ./src/main/java/JPM
102102
<version>23.0.0</version>
103103
<scope>compile</scope>
104104
</dependency>
105+
<dependency>
106+
<groupId>com.google.http-client</groupId>
107+
<artifactId>google-http-client</artifactId>
108+
<version>1.42.0</version>
109+
<scope>compile</scope>
110+
</dependency>
111+
<dependency>
112+
<groupId>org.apache.httpcomponents</groupId>
113+
<artifactId>httpcore</artifactId>
114+
<version>4.4.15</version>
115+
<scope>compile</scope>
116+
</dependency>
117+
<dependency>
118+
<groupId>com.google.http-client</groupId>
119+
<artifactId>google-http-client-gson</artifactId>
120+
<version>1.42.1</version>
121+
<scope>compile</scope>
122+
</dependency>
123+
<dependency>
124+
<groupId>com.google.guava</groupId>
125+
<artifactId>guava</artifactId>
126+
<version>31.1-jre</version>
127+
<scope>compile</scope>
128+
</dependency>
129+
<dependency>
130+
<groupId>com.google.errorprone</groupId>
131+
<artifactId>error_prone_annotations</artifactId>
132+
<version>2.27.0</version>
133+
<scope>compile</scope>
134+
</dependency>
135+
<dependency>
136+
<groupId>com.google.code.gson</groupId>
137+
<artifactId>gson</artifactId>
138+
<version>2.11.0</version>
139+
<scope>compile</scope>
140+
</dependency>
105141
</dependencies>
106142
</dependencyManagement>
107143
<dependencies>
@@ -261,6 +297,24 @@ AUTO-GENERATED FILE, CHANGES SHOULD BE DONE IN ./JPM.java or ./src/main/java/JPM
261297
<version>20250107</version>
262298
<scope>compile</scope>
263299
</dependency>
300+
<dependency>
301+
<groupId>com.google.api-client</groupId>
302+
<artifactId>google-api-client</artifactId>
303+
<version>2.0.0</version>
304+
<scope>compile</scope>
305+
</dependency>
306+
<dependency>
307+
<groupId>com.google.oauth-client</groupId>
308+
<artifactId>google-oauth-client-jetty</artifactId>
309+
<version>1.34.1</version>
310+
<scope>compile</scope>
311+
</dependency>
312+
<dependency>
313+
<groupId>com.google.apis</groupId>
314+
<artifactId>google-api-services-drive</artifactId>
315+
<version>v3-rev20220815-2.0.0</version>
316+
<scope>compile</scope>
317+
</dependency>
264318
<dependency>
265319
<groupId>org.nanohttpd</groupId>
266320
<artifactId>nanohttpd</artifactId>

src/main/java/JPM.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public ThisProject(List<String> args) {
2121
// Override default configurations
2222
this.groupId = "com.osiris.autoplug.client";
2323
this.artifactId = "AutoPlug-Client";
24-
this.version = "8.3.2";
24+
this.version = "8.3.3";
2525
this.mainClass = "com.osiris.autoplug.client.Main";
2626
this.jarName = "AutoPlug-Client-original.jar";
2727
this.fatJarName = "AutoPlug-Client.jar";
@@ -75,6 +75,17 @@ public ThisProject(List<String> args) {
7575
implementation("org.apache.sshd:sshd-core:2.13.0");
7676
implementation("org.json:json:20250107");
7777

78+
// Google Drive
79+
implementation("com.google.api-client:google-api-client:2.0.0");
80+
implementation("com.google.oauth-client:google-oauth-client-jetty:1.34.1");
81+
implementation("com.google.apis:google-api-services-drive:v3-rev20220815-2.0.0");
82+
forceImplementation("com.google.http-client:google-http-client:1.42.0");
83+
forceImplementation("org.apache.httpcomponents:httpcore:4.4.15");
84+
forceImplementation("com.google.http-client:google-http-client-gson:1.42.1");
85+
forceImplementation("com.google.guava:guava:31.1-jre");
86+
forceImplementation("com.google.errorprone:error_prone_annotations:2.27.0");
87+
forceImplementation("com.google.code.gson:gson:2.11.0");
88+
7889
// Minecraft client:
7990
implementation("org.nanohttpd:nanohttpd:2.3.1");
8091
implementation("org.glavo.kala:kala-compress:1.27.1-1");

src/main/java/com/osiris/autoplug/client/configs/BackupConfig.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
package com.osiris.autoplug.client.configs;
1010

11+
import com.osiris.autoplug.client.network.online.connections.ConAutoPlugConsoleSend;
12+
import com.osiris.autoplug.client.tasks.backup.BackupGoogleDrive;
1113
import com.osiris.autoplug.client.utils.UtilsFile;
1214
import com.osiris.dyml.Yaml;
1315
import com.osiris.dyml.YamlSection;
@@ -18,6 +20,7 @@
1820
import java.io.IOException;
1921
import java.util.ArrayList;
2022
import java.util.List;
23+
import java.util.concurrent.atomic.AtomicBoolean;
2124

2225
public class BackupConfig extends MyYaml {
2326
private static final boolean isFileListenerRegistered = false;
@@ -38,12 +41,29 @@ public class BackupConfig extends MyYaml {
3841
public YamlSection backup_upload_password;
3942
public YamlSection backup_upload_path;
4043
public YamlSection backup_upload_rsa;
44+
public YamlSection backup_upload_alternatives_google_drive;
45+
public YamlSection backup_upload_alternatives_google_drive_enable;
46+
public YamlSection backup_upload_alternatives_google_drive_client_id;
47+
public YamlSection backup_upload_alternatives_google_drive_client_secret;
48+
public YamlSection backup_upload_alternatives_google_drive_refresh_token;
4149

50+
public static final AtomicBoolean isGoogleDriveEnabled = new AtomicBoolean(false);
4251

4352
public BackupConfig() throws IOException, DuplicateKeyException, YamlReaderException, IllegalListException, NotLoadedException, IllegalKeyException, YamlWriterException {
4453
super(System.getProperty("user.dir") + "/autoplug/backup.yml");
4554

4655
addSingletonConfigFileEventListener(e -> {
56+
boolean newVal = this.backup_upload_alternatives_google_drive_enable.asBoolean();
57+
if(isGoogleDriveEnabled.get() != newVal && newVal == true){
58+
// Changed from false to true, meaning enabled, thus check if we need to do credential fetching
59+
try{
60+
BackupGoogleDrive backupGoogleDrive = new BackupGoogleDrive();
61+
backupGoogleDrive.getCredentials(this);
62+
} catch (Exception ex) {
63+
AL.warn(ex);
64+
}
65+
}
66+
isGoogleDriveEnabled.set(newVal);
4767
});
4868

4969
lockFile();
@@ -116,6 +136,31 @@ public BackupConfig() throws IOException, DuplicateKeyException, YamlReaderExcep
116136
"Otherwise enter a relative or absolute path to the file containing the key.",
117137
"Usually the path is something like this: /home/username/.ssh/id_rsa");
118138

139+
backup_upload_alternatives_google_drive = put(name, "upload", "alternatives", "google-drive").setComments("" +
140+
"How This Works:\n" +
141+
"1. You create OAuth credentials in your own Google Cloud Console\n" +
142+
"2. You enter your Client ID and Client Secret in the sections below\n" +
143+
"3. You get an URL to open with your browser and log in\n" +
144+
"4. After authentication, a refresh token is saved for future use and to avoid repeating the steps shown below\n" +
145+
"Google-Drive Setup:\n" +
146+
"1. Create a project in Google Cloud Console (or use an existing one) and make sure the project_id is autoplug-client: https://developers.google.com/workspace/guides/create-project\n" +
147+
"2. Enable the Google Drive API: https://console.cloud.google.com/flows/enableapi?apiid=drive.googleapis.com\n" +
148+
"3. Create OAuth 2.0 login panel: https://console.cloud.google.com/auth/branding\n" +
149+
"4. Create a Client (type \"Desktop app\"): https://console.cloud.google.com/auth/clients\n" +
150+
"5. Add urn:ietf:wg:oauth:2.0:oob as authorized redirect URI\n" +
151+
"6. Enter your Client ID and Client Secret into the sections below\n" +
152+
"7. Set 'enable' to 'true' and save this file" +
153+
"8. An URL should be shown in your console, open it via your browser and authenticate, then paste the code back into the console\n" +
154+
"9. After authentication, the backups will be uploaded to your personal Google Drive\n" +
155+
"!!!IMPORTANT!!! This file now contains data that must be kept secret, do not share with anyone!\n");
156+
backup_upload_alternatives_google_drive_enable = put(name, "upload", "alternatives", "google-drive", "enable").setDefValues("false");
157+
backup_upload_alternatives_google_drive_client_id = put(name, "upload", "alternatives", "google-drive", "client-id").setComments(
158+
"Get this from Google Cloud Console after creating OAuth credentials.");
159+
backup_upload_alternatives_google_drive_client_secret = put(name, "upload", "alternatives", "google-drive", "client-secret").setComments(
160+
"Get this from Google Cloud Console after creating OAuth credentials.");
161+
backup_upload_alternatives_google_drive_refresh_token = put(name, "upload", "alternatives", "google-drive", "refresh-token").setComments(
162+
"This will be automatically obtained during first-time setup.");
163+
119164
save();
120165
unlockFile();
121166
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.osiris.autoplug.client.tasks.backup;
2+
3+
import com.google.api.client.auth.oauth2.Credential;
4+
import com.google.api.client.auth.oauth2.TokenResponse;
5+
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
6+
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
7+
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
8+
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
9+
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
10+
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
11+
import com.google.api.client.http.FileContent;
12+
import com.google.api.client.http.javanet.NetHttpTransport;
13+
import com.google.api.client.json.JsonFactory;
14+
import com.google.api.client.json.gson.GsonFactory;
15+
import com.google.api.client.util.store.FileDataStoreFactory;
16+
import com.google.api.services.drive.Drive;
17+
import com.google.api.services.drive.DriveScopes;
18+
import com.google.api.services.drive.model.File;
19+
import com.osiris.autoplug.client.configs.BackupConfig;
20+
import com.osiris.jlib.logger.AL;
21+
22+
import java.io.IOException;
23+
import java.io.InputStreamReader;
24+
import java.security.GeneralSecurityException;
25+
import java.util.Collections;
26+
27+
public class BackupGoogleDrive {
28+
29+
final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
30+
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
31+
32+
public BackupGoogleDrive() throws GeneralSecurityException, IOException {
33+
}
34+
35+
public Credential getCredentials(BackupConfig config) throws Exception {
36+
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(
37+
GsonFactory.getDefaultInstance(),
38+
new InputStreamReader(new java.io.ByteArrayInputStream(
39+
("{\"installed\":{\"client_id\":\"" + config.backup_upload_alternatives_google_drive_client_id.asString() + "\"," +
40+
"\"project_id\":\"autoplug-client\",\"auth_uri\":\"https://accounts.google.com/o/oauth2/auth\"," +
41+
"\"token_uri\":\"https://oauth2.googleapis.com/token\"," +
42+
"\"auth_provider_x509_cert_url\":\"https://www.googleapis.com/oauth2/v1/certs\"," +
43+
"\"client_secret\":\"" + config.backup_upload_alternatives_google_drive_client_secret.asString() + "\"," +
44+
"\"redirect_uris\":[\"urn:ietf:wg:oauth:2.0:oob\"]}").getBytes())));
45+
46+
// Try to use refresh token if available
47+
if (config.backup_upload_alternatives_google_drive_refresh_token.asString() != null &&
48+
!config.backup_upload_alternatives_google_drive_refresh_token.asString().isEmpty()) {
49+
TokenResponse response = new TokenResponse();
50+
response.setRefreshToken(config.backup_upload_alternatives_google_drive_refresh_token.asString());
51+
return new GoogleCredential.Builder()
52+
.setTransport(HTTP_TRANSPORT)
53+
.setJsonFactory(JSON_FACTORY)
54+
.setClientSecrets(clientSecrets)
55+
.build()
56+
.setFromTokenResponse(response);
57+
}
58+
59+
// Manual authorization flow
60+
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
61+
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets,
62+
Collections.singleton(DriveScopes.DRIVE_FILE))
63+
.setAccessType("offline")
64+
.build();
65+
66+
String url = flow.newAuthorizationUrl()
67+
.setRedirectUri("urn:ietf:wg:oauth:2.0:oob")
68+
.build();
69+
70+
AL.info("Please open this URL in your browser: " + url);
71+
AL.info("After authorization, paste the code you received here and press enter:");
72+
73+
// Read code from console input
74+
String code = new java.util.Scanner(System.in).nextLine();
75+
76+
TokenResponse response = flow.newTokenRequest(code)
77+
.setRedirectUri("urn:ietf:wg:oauth:2.0:oob")
78+
.execute();
79+
80+
Credential credential = flow.createAndStoreCredential(response, "user");
81+
82+
// Save refresh token for future use
83+
if (credential.getRefreshToken() != null) {
84+
config.backup_upload_alternatives_google_drive_refresh_token.setValues(credential.getRefreshToken());
85+
config.save();
86+
}
87+
88+
return credential;
89+
}
90+
91+
// Modify the uploadToGoogleDrive method
92+
public void uploadToGoogleDrive(java.io.File fileToUpload, BackupConfig config)
93+
throws Exception {
94+
if (!config.backup_upload_alternatives_google_drive_enable.asBoolean()) {
95+
throw new IOException("Google Drive upload is not enabled");
96+
}
97+
98+
// Get credentials
99+
Credential credential = getCredentials(config);
100+
101+
// Create Drive service
102+
Drive drive = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
103+
.setApplicationName("AutoPlug-Client")
104+
.build();
105+
106+
// Rest of the upload logic remains the same...
107+
File fileMetadata = new File();
108+
fileMetadata.setName(fileToUpload.getName());
109+
String folderId = config.backup_upload_path.asString();
110+
if (folderId != null && !folderId.isEmpty()) {
111+
fileMetadata.setParents(Collections.singletonList(folderId));
112+
}
113+
114+
FileContent mediaContent = new FileContent("application/zip", fileToUpload);
115+
File uploadedFile = drive.files().create(fileMetadata, mediaContent)
116+
.setFields("id")
117+
.execute();
118+
119+
AL.debug(this.getClass(), "Uploaded to Google Drive with ID: " + uploadedFile.getId());
120+
121+
if (config.backup_upload_delete_on_complete.asBoolean()) {
122+
fileToUpload.delete();
123+
}
124+
}
125+
}

src/main/java/com/osiris/autoplug/client/tasks/backup/TaskBackup.java

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -162,22 +162,31 @@ private void createBackup() throws Exception {
162162

163163
setStatus("Uploading server-files backup...");
164164

165-
Upload upload = new Upload(config.backup_upload_host.asString(),
166-
config.backup_upload_port.asInt(),
167-
config.backup_upload_user.asString(),
168-
config.backup_upload_password.asString(),
169-
config.backup_upload_path.asString(),
170-
zip.getFile());
171-
172-
String rsa = config.backup_upload_rsa.asString();
173-
try {
174-
if (rsa == null || rsa.trim().isEmpty()) upload.ftps();
175-
else upload.sftp(rsa.trim());
165+
if(config.backup_upload_alternatives_google_drive_enable.asBoolean()){
166+
try{
167+
BackupGoogleDrive backupGoogleDrive = new BackupGoogleDrive();
168+
backupGoogleDrive.uploadToGoogleDrive(zip.getFile(), config);
169+
} catch (Exception e) {
170+
getWarnings().add(new BWarning(this, e, "Failed to upload backup."));
171+
}
172+
} else{
173+
Upload upload = new Upload(config.backup_upload_host.asString(),
174+
config.backup_upload_port.asInt(),
175+
config.backup_upload_user.asString(),
176+
config.backup_upload_password.asString(),
177+
config.backup_upload_path.asString(),
178+
zip.getFile());
179+
180+
String rsa = config.backup_upload_rsa.asString();
181+
try {
182+
if (rsa == null || rsa.trim().isEmpty()) upload.ftps();
183+
else upload.sftp(rsa.trim());
176184

177-
if (config.backup_upload_delete_on_complete.asBoolean())
178-
zip.getFile().delete();
179-
} catch (Exception e) {
180-
getWarnings().add(new BWarning(this, e, "Failed to upload backup."));
185+
if (config.backup_upload_delete_on_complete.asBoolean())
186+
zip.getFile().delete();
187+
} catch (Exception e) {
188+
getWarnings().add(new BWarning(this, e, "Failed to upload backup."));
189+
}
181190
}
182191

183192
if (getWarnings().size() > 0)

0 commit comments

Comments
 (0)