Documented helper classes in util package

Also did minor code cleanup
This commit is contained in:
2023-01-27 20:13:01 +01:00
parent 5f6732b8ea
commit 6eabc0a22f
6 changed files with 63 additions and 5 deletions

View File

@@ -15,18 +15,28 @@ import java.security.spec.KeySpec;
public class CryptoHelper { public class CryptoHelper {
/**
* Creates a <code>javax.crypto.SecretKey</code> from a provided password
* @param pass The password
* @return the generated secret key
*/
public static SecretKey createKeyFromPassword(String pass){ public static SecretKey createKeyFromPassword(String pass){
try { try {
KeySpec spec = new PBEKeySpec(pass.toCharArray(), "abcdefghijklmnop".getBytes(), 65536, 256); // AES-256 KeySpec spec = new PBEKeySpec(pass.toCharArray(), "abcdefghijklmnop".getBytes(), 65536, 256); // AES-256
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] key = new byte[0]; byte[] key = f.generateSecret(spec).getEncoded();
key = f.generateSecret(spec).getEncoded();
return new SecretKeySpec(key, "AES"); return new SecretKeySpec(key, "AES");
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) { } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
/**
* Saves a <code>java.io.Serializable</code> Object into an encrypted file
* @param obj The object to save
* @param file The Path where to save the file
* @param key The SecretKey (AES) to encrypt the file with
*/
public static void serializeEncrypted(Serializable obj, Path file, SecretKey key){ public static void serializeEncrypted(Serializable obj, Path file, SecretKey key){
try { try {
if(file.toFile().exists()) file.toFile().delete(); if(file.toFile().exists()) file.toFile().delete();
@@ -45,8 +55,14 @@ public class CryptoHelper {
} }
} }
/**
* Reads an encrypted file into a <code>java.io.Serializable</code> object.
* @param file The <code>java.nio.Path</code> where the encrypted file is stored.
* @param key The SecretKey (AES) to decrypt the file with
* @return The <code>java.io.Serializable</code> object read from the file.
*/
public static Serializable deserializeEncrypted(Path file, SecretKey key) { public static Serializable deserializeEncrypted(Path file, SecretKey key) {
Serializable ret = null; Serializable ret;
try { try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec("abcdefghijklmnop".getBytes()); IvParameterSpec iv = new IvParameterSpec("abcdefghijklmnop".getBytes());

View File

@@ -7,6 +7,11 @@ import java.util.Base64;
public class FileHelper { public class FileHelper {
/**
* Reads a file and encodes it into Base64
* @param file The file to read
* @return A Base64 encoded String containing the data of the file
*/
public static String encodeFileToBase64(File file){ public static String encodeFileToBase64(File file){
String encodedfile = null; String encodedfile = null;
try (FileInputStream fileInputStreamReader = new FileInputStream(file)){ try (FileInputStream fileInputStreamReader = new FileInputStream(file)){

View File

@@ -4,6 +4,11 @@ import static de.b00tload.tools.lastfmtospotifyplaylist.LastFMToSpotify.configur
public class Logger { public class Logger {
/**
* Logs the provided String to console if the option <code>logging.level</code> in the configuration is higher or equal to the provided priority
* @param string The String to log
* @param priority The minimum logging level with which the provided string should be logged
*/
public static void logLn(String string, int priority){ public static void logLn(String string, int priority){
if(Integer.parseInt(configuration.get("logging.level"))>=priority){ if(Integer.parseInt(configuration.get("logging.level"))>=priority){
System.out.println(string); System.out.println(string);

View File

@@ -4,6 +4,11 @@ import de.umass.lastfm.Period;
public class PeriodHelper { public class PeriodHelper {
/**
* Converts a provided String (<code>de.umass.lastfm.Period.getString()</code>) into the corresponding <code>de.umass.lastfm.Period</code>
* @param string The value to be converted into a <code>de.umass.lastfm.Period</code>
* @return The converted <code>de.umass.lastfm.Period</code>, defaults to <code>de.umass.lastfm.Period.ONE_MONTH</code>
*/
public static Period getPeriodByString(String string){ public static Period getPeriodByString(String string){
for(Period p : Period.values()){ for(Period p : Period.values()){
if(p.getString().equalsIgnoreCase(string)) return p; if(p.getString().equalsIgnoreCase(string)) return p;

View File

@@ -5,19 +5,33 @@ import java.time.ZoneId;
public class TimeHelper { public class TimeHelper {
/**
* Gets the hours of the UTC offset from a LocalDateTime, which is asserted to be at the system default Timezone (<code>ZoneId.systemDefault()</code>)
* @param now The <code>java.time.LocalDateTime</code> for which the offset should be calculated
* @return The hours of offset from UTC
*/
public static int getUTCOffsetHours(LocalDateTime now){ public static int getUTCOffsetHours(LocalDateTime now){
return (int) Math.floor((double) now.atZone(ZoneId.systemDefault()).getOffset().getTotalSeconds()/3600); return (int) Math.floor((double) now.atZone(ZoneId.systemDefault()).getOffset().getTotalSeconds()/3600);
} }
/**
* Gets the minutes of the UTC offset from a LocalDateTime, which is asserted to be at the system default Timezone (<code>ZoneId.systemDefault()</code>)
* @param now The <code>java.time.LocalDateTime</code> for which the offset should be calculated
* @return The minutes of offset from UTC
*/
public static int getUTCOffsetMinutes(LocalDateTime now){ public static int getUTCOffsetMinutes(LocalDateTime now){
return (now.atZone(ZoneId.systemDefault()).getOffset().getTotalSeconds()/60); return (now.atZone(ZoneId.systemDefault()).getOffset().getTotalSeconds()/60);
} }
/**
* Generates an ISO 8601 complying String containing the UTC offset from a LocalDateTime, which is asserted to be at the system default Timezone (<code>ZoneId.systemDefault()</code>)
* @param now The <code>java.time.LocalDateTime</code> for which the offset should be calculated
* @return an ISO 8601 complying String containing the UTC offset (e.g. "+01:00")
*/
public static String getUTCOffset(LocalDateTime now){ public static String getUTCOffset(LocalDateTime now){
int hour = getUTCOffsetHours(now); int hour = getUTCOffsetHours(now);
String h = (hour == Math.abs(hour) ? "+" : "-") + (String.valueOf(Math.abs(hour)).length() == 1 ? "0" + Math.abs(hour) : String.valueOf(Math.abs(hour))); String h = (hour == Math.abs(hour) ? "+" : "-") + (String.valueOf(Math.abs(hour)).length() == 1 ? "0" + Math.abs(hour) : String.valueOf(Math.abs(hour)));
int min = Math.abs(getUTCOffsetMinutes(now))-(Math.abs(hour)*60); int min = Math.abs(getUTCOffsetMinutes(now))%(Math.abs(hour));
String m = (String.valueOf(Math.abs(min)).length() == 1 ? "0" + Math.abs(min) : String.valueOf(Math.abs(min))); String m = (String.valueOf(Math.abs(min)).length() == 1 ? "0" + Math.abs(min) : String.valueOf(Math.abs(min)));
return h + ":" + m; return h + ":" + m;
} }

View File

@@ -8,14 +8,27 @@ import static de.b00tload.tools.lastfmtospotifyplaylist.LastFMToSpotify.USER_HOM
import static de.b00tload.tools.lastfmtospotifyplaylist.LastFMToSpotify.configuration; import static de.b00tload.tools.lastfmtospotifyplaylist.LastFMToSpotify.configuration;
public class TokenHelper { public class TokenHelper {
/**
* Manages saving a <code>se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials</code> into "~/.lfm2s/spotify.lfm2scred" using <code>de.b00tload.tools.lastfmtospotifyplaylist.util.CryptoHelper.serializeEncrypted(...)</code>
* @param cred The <code>se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials</code> to be saved
*/
public static void saveTokens(AuthorizationCodeCredentials cred) { public static void saveTokens(AuthorizationCodeCredentials cred) {
CryptoHelper.serializeEncrypted(cred, Path.of(USER_HOME, "/.lfm2s/spotify.lfm2scred"), CryptoHelper.createKeyFromPassword(configuration.get("cache.crypto"))); CryptoHelper.serializeEncrypted(cred, Path.of(USER_HOME, "/.lfm2s/spotify.lfm2scred"), CryptoHelper.createKeyFromPassword(configuration.get("cache.crypto")));
} }
/**
* Manages retrieving a <code>se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials</code> from "~/.lfm2s/spotify.lfm2scred" using <code>de.b00tload.tools.lastfmtospotifyplaylist.util.CryptoHelper.deserializeEncrypted(...)</code>
* @return The retrieved <code>se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials</code>
*/
public static AuthorizationCodeCredentials fetchTokens() { public static AuthorizationCodeCredentials fetchTokens() {
return (AuthorizationCodeCredentials) CryptoHelper.deserializeEncrypted(Path.of(USER_HOME, "/.lfm2s/spotify.lfm2scred"), CryptoHelper.createKeyFromPassword(configuration.get("cache.crypto"))); return (AuthorizationCodeCredentials) CryptoHelper.deserializeEncrypted(Path.of(USER_HOME, "/.lfm2s/spotify.lfm2scred"), CryptoHelper.createKeyFromPassword(configuration.get("cache.crypto")));
} }
/**
* Checks whether the saved spotify AuthorizationCodeCredentials at "~/.lfm2s/spotify.lfm2scred" exist
* @return true if file exists, false if not
*/
public static boolean existsTokens(){ public static boolean existsTokens(){
return Path.of(USER_HOME, "/.lfm2s/spotify.lfm2scred").toFile().exists(); return Path.of(USER_HOME, "/.lfm2s/spotify.lfm2scred").toFile().exists();
} }