-
Notifications
You must be signed in to change notification settings - Fork 466
feat: add Android 19 compatible FileDataStoreFactory implementation #1070
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
0d4bc5c
ci: add a animal sniffer check configuration for Android API level 19
chingor13 a8537c9
build(deps): update animal-sniffer-maven-plugin version
chingor13 cdaf1ea
feat: add Android comptible FileDataStoreFactory implementation
chingor13 e90753a
ci: allow java.nio.file in google-http-client
chingor13 9e52cce
chore: fix lint
chingor13 ef67a51
build: put animal-sniffer-maven-plugin back to 1.17
chingor13 ac2e9d2
fix: remove reflection from file permission settings
chingor13 932e50a
chore: run formatter
chingor13 da13906
chore: remove docs mentioning Java 1.5
chingor13 a3868b0
fix: move member assignment after input validation
chingor13 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat: add Android comptible FileDataStoreFactory implementation
This is branched from the original implementation prior to switching to NIO for Windows compatibility.
- Loading branch information
commit cdaf1eabcefc7232c82d492acc5b56e313f9a85f
There are no files selected for viewing
161 changes: 161 additions & 0 deletions
161
...c/main/java/com/google/api/client/extensions/android/util/store/FileDataStoreFactory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| /* | ||
| * Copyright 2020 Google LLC | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * https://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.google.api.client.extensions.android.util.store; | ||
|
|
||
| import com.google.api.client.util.IOUtils; | ||
| import com.google.api.client.util.Maps; | ||
| import com.google.api.client.util.Throwables; | ||
| import com.google.api.client.util.store.AbstractDataStoreFactory; | ||
| import com.google.api.client.util.store.AbstractMemoryDataStore; | ||
| import com.google.api.client.util.store.DataStore; | ||
| import java.io.File; | ||
| import java.io.FileInputStream; | ||
| import java.io.FileOutputStream; | ||
| import java.io.IOException; | ||
| import java.io.Serializable; | ||
| import java.lang.reflect.InvocationTargetException; | ||
| import java.lang.reflect.Method; | ||
| import java.util.logging.Logger; | ||
|
|
||
| /** | ||
| * Thread-safe file implementation of a credential store. | ||
| * | ||
| * <p>For security purposes, the file's permissions are set to be accessible only by the file's | ||
| * owner. Note that Java 1.5 does not support manipulating file permissions, and must be done | ||
| * manually or using the JNI. | ||
| * | ||
| * <p>Note: This class was branched from the primary implementation in google-http-client to allow | ||
| * the mainline implementation to support Windows file permissions. | ||
| * | ||
| * @since 1.36 | ||
| * @author Yaniv Inbar | ||
| */ | ||
| public class FileDataStoreFactory extends AbstractDataStoreFactory { | ||
|
|
||
| private static final Logger LOGGER = Logger.getLogger(FileDataStoreFactory.class.getName()); | ||
|
|
||
| /** Directory to store data. */ | ||
| private final File dataDirectory; | ||
|
|
||
| /** @param dataDirectory data directory */ | ||
| public FileDataStoreFactory(File dataDirectory) throws IOException { | ||
| dataDirectory = dataDirectory.getCanonicalFile(); | ||
| this.dataDirectory = dataDirectory; | ||
| // error if it is a symbolic link | ||
| if (IOUtils.isSymbolicLink(dataDirectory)) { | ||
chingor13 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| throw new IOException("unable to use a symbolic link: " + dataDirectory); | ||
| } | ||
| // create parent directory (if necessary) | ||
| if (!dataDirectory.exists() && !dataDirectory.mkdirs()) { | ||
| throw new IOException("unable to create directory: " + dataDirectory); | ||
| } | ||
| setPermissionsToOwnerOnly(dataDirectory); | ||
| } | ||
|
|
||
| /** Returns the data directory. */ | ||
| public final File getDataDirectory() { | ||
| return dataDirectory; | ||
| } | ||
|
|
||
| @Override | ||
| protected <V extends Serializable> DataStore<V> createDataStore(String id) throws IOException { | ||
| return new FileDataStore<V>(this, dataDirectory, id); | ||
| } | ||
|
|
||
| /** | ||
| * File data store that inherits from the abstract memory data store because the key-value pairs | ||
| * are stored in a memory cache, and saved in the file (see {@link #save()} when changing values. | ||
| * | ||
| * @param <V> serializable type of the mapped value | ||
| */ | ||
| static class FileDataStore<V extends Serializable> extends AbstractMemoryDataStore<V> { | ||
|
|
||
| /** File to store data. */ | ||
| private final File dataFile; | ||
|
|
||
| FileDataStore(FileDataStoreFactory dataStore, File dataDirectory, String id) | ||
| throws IOException { | ||
| super(dataStore, id); | ||
| this.dataFile = new File(dataDirectory, id); | ||
| // error if it is a symbolic link | ||
| if (IOUtils.isSymbolicLink(dataFile)) { | ||
| throw new IOException("unable to use a symbolic link: " + dataFile); | ||
| } | ||
| // create new file (if necessary) | ||
| if (dataFile.createNewFile()) { | ||
| keyValueMap = Maps.newHashMap(); | ||
| // save the credentials to create a new file | ||
| save(); | ||
| } else { | ||
| // load credentials from existing file | ||
| keyValueMap = IOUtils.deserialize(new FileInputStream(dataFile)); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void save() throws IOException { | ||
| IOUtils.serialize(keyValueMap, new FileOutputStream(dataFile)); | ||
| } | ||
|
|
||
| @Override | ||
| public FileDataStoreFactory getDataStoreFactory() { | ||
| return (FileDataStoreFactory) super.getDataStoreFactory(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Attempts to set the given file's permissions such that it can only be read, written, and | ||
| * executed by the file's owner. | ||
| * | ||
| * @param file the file's permissions to modify | ||
| * @throws IOException | ||
| */ | ||
| static void setPermissionsToOwnerOnly(File file) throws IOException { | ||
| // Disable access by other users if O/S allows it and set file permissions to readable and | ||
| // writable by user. Use reflection since JDK 1.5 will not have these methods | ||
| try { | ||
| Method setReadable = File.class.getMethod("setReadable", boolean.class, boolean.class); | ||
| Method setWritable = File.class.getMethod("setWritable", boolean.class, boolean.class); | ||
| Method setExecutable = File.class.getMethod("setExecutable", boolean.class, boolean.class); | ||
| if (!(Boolean) setReadable.invoke(file, false, false) | ||
| || !(Boolean) setWritable.invoke(file, false, false) | ||
| || !(Boolean) setExecutable.invoke(file, false, false)) { | ||
| LOGGER.warning("unable to change permissions for everybody: " + file); | ||
| } | ||
| if (!(Boolean) setReadable.invoke(file, true, true) | ||
| || !(Boolean) setWritable.invoke(file, true, true) | ||
| || !(Boolean) setExecutable.invoke(file, true, true)) { | ||
| LOGGER.warning("unable to change permissions for owner: " + file); | ||
| } | ||
| } catch (InvocationTargetException exception) { | ||
| Throwable cause = exception.getCause(); | ||
| Throwables.propagateIfPossible(cause, IOException.class); | ||
| // shouldn't reach this point, but just in case... | ||
| throw new RuntimeException(cause); | ||
| } catch (NoSuchMethodException exception) { | ||
| LOGGER.warning( | ||
| "Unable to set permissions for " | ||
| + file | ||
| + ", likely because you are running a version of Java prior to 1.6"); | ||
chingor13 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } catch (SecurityException exception) { | ||
| // ignored | ||
| } catch (IllegalAccessException exception) { | ||
| // ignored | ||
| } catch (IllegalArgumentException exception) { | ||
| // ignored | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.