17 Invalid refresh token #20
@@ -6,6 +6,7 @@ import de.b00tload.tools.lastfmtospotifyplaylist.arguments.ArgumentHandler;
|
|||||||
import de.b00tload.tools.lastfmtospotifyplaylist.arguments.Arguments;
|
import de.b00tload.tools.lastfmtospotifyplaylist.arguments.Arguments;
|
||||||
import de.b00tload.tools.lastfmtospotifyplaylist.util.PeriodHelper;
|
import de.b00tload.tools.lastfmtospotifyplaylist.util.PeriodHelper;
|
||||||
|
|
||||||
|
import de.b00tload.tools.lastfmtospotifyplaylist.util.SpotifyCredentials;
|
||||||
import de.b00tload.tools.lastfmtospotifyplaylist.util.TokenHelper;
|
import de.b00tload.tools.lastfmtospotifyplaylist.util.TokenHelper;
|
||||||
import de.umass.lastfm.Caller;
|
import de.umass.lastfm.Caller;
|
||||||
import de.umass.lastfm.Track;
|
import de.umass.lastfm.Track;
|
||||||
@@ -14,7 +15,6 @@ import io.javalin.Javalin;
|
|||||||
import io.javalin.http.ContentType;
|
import io.javalin.http.ContentType;
|
||||||
import io.javalin.http.HttpStatus;
|
import io.javalin.http.HttpStatus;
|
||||||
import se.michaelthelin.spotify.SpotifyApi;
|
import se.michaelthelin.spotify.SpotifyApi;
|
||||||
import se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials;
|
|
||||||
import se.michaelthelin.spotify.model_objects.specification.Playlist;
|
import se.michaelthelin.spotify.model_objects.specification.Playlist;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -82,11 +82,16 @@ public class LastFMToSpotify {
|
|||||||
AtomicBoolean waiting = new AtomicBoolean(true);
|
AtomicBoolean waiting = new AtomicBoolean(true);
|
||||||
if (configuration.containsKey("cache.crypto") && TokenHelper.existsTokens()) {
|
if (configuration.containsKey("cache.crypto") && TokenHelper.existsTokens()) {
|
||||||
logLn("Cached credentials have been found.", 2);
|
logLn("Cached credentials have been found.", 2);
|
||||||
logLn("Fetching old credentials, refreshing them and saving to cache", 2);
|
logLn("Fetching credentials from cache.", 2);
|
||||||
AuthorizationCodeCredentials oldcred = TokenHelper.fetchTokens();
|
SpotifyCredentials cred = TokenHelper.fetchTokens();
|
||||||
AuthorizationCodeCredentials newcred = api.authorizationCodeRefresh(api.getClientId(), api.getClientSecret(), oldcred.getRefreshToken()).setHeader("User-Agent", configuration.get("requests.useragent")).build().execute();
|
api.setRefreshToken(cred.getRefreshToken());
|
||||||
TokenHelper.saveTokens(newcred);
|
|
||||||
configuration.put("spotify.access", newcred.getAccessToken());
|
if(!cred.isValid()){
|
||||||
|
logLn("Cached credentials are invalid due to age. Refreshing and saving to cache", 2);
|
||||||
|
cred.refreshCredentials(api.authorizationCodeRefresh().build().execute());
|
||||||
|
TokenHelper.saveTokens(cred);
|
||||||
|
}
|
||||||
|
configuration.put("spotify.access", cred.getAccessToken());
|
||||||
} else {
|
} else {
|
||||||
try (Javalin webserver = Javalin.create().start(9876)) {
|
try (Javalin webserver = Javalin.create().start(9876)) {
|
||||||
if (configuration.containsKey("cache.crypto")) logLn("No cached credentials have been found.", 2);
|
if (configuration.containsKey("cache.crypto")) logLn("No cached credentials have been found.", 2);
|
||||||
@@ -98,7 +103,7 @@ public class LastFMToSpotify {
|
|||||||
webserver.get("/callback/spotify", ctx -> {
|
webserver.get("/callback/spotify", ctx -> {
|
||||||
if(ctx.queryParamMap().containsKey("code")) {
|
if(ctx.queryParamMap().containsKey("code")) {
|
||||||
logLn("Received spotify authentication code. Requesting credentials.", 2);
|
logLn("Received spotify authentication code. Requesting credentials.", 2);
|
||||||
AuthorizationCodeCredentials cred = api.authorizationCode(ctx.queryParam("code")).setHeader("User-Agent", configuration.get("requests.useragent")).build().execute();
|
SpotifyCredentials cred = new SpotifyCredentials(api.authorizationCode(ctx.queryParam("code")).setHeader("User-Agent", configuration.get("requests.useragent")).build().execute());
|
||||||
configuration.put("spotify.access", cred.getAccessToken());
|
configuration.put("spotify.access", cred.getAccessToken());
|
||||||
if(configuration.containsKey("cache.crypto")) {
|
if(configuration.containsKey("cache.crypto")) {
|
||||||
logLn("Saving credentials to cache.", 2);
|
logLn("Saving credentials to cache.", 2);
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package de.b00tload.tools.lastfmtospotifyplaylist.util;
|
||||||
|
import se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper class for <code>se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials</code>. Implements checking validity of access token.
|
||||||
|
*/
|
||||||
|
public class SpotifyCredentials implements Serializable {
|
||||||
|
|
||||||
|
private String accessToken;
|
||||||
|
private String refreshToken;
|
||||||
|
private LocalDateTime validUntil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the class
|
||||||
|
* @param cred The <code>AuthorizationCodeCredentials</code> to be saved. Recommended for use with recently (last few seconds) generated Credentials
|
||||||
|
*/
|
||||||
|
public SpotifyCredentials(AuthorizationCodeCredentials cred){
|
||||||
|
this.accessToken = cred.getAccessToken();
|
||||||
|
this.refreshToken = cred.getRefreshToken();
|
||||||
|
this.validUntil = LocalDateTime.now(Clock.systemDefaultZone()).plusSeconds(cred.getExpiresIn());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the access token. It becomes invalid after a certain period of time. Check validity with <code>isValid()</code>.
|
||||||
|
* @return An access token that can be provided in subsequent calls, for example to Spotify Web API services.
|
||||||
|
*/
|
||||||
|
public String getAccessToken(){
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the refresh token. This token can be sent to the Spotify Accounts service in place of an authorization code to retrieve a new access token.
|
||||||
|
* @return A token that can be sent to the Spotify Accounts service in place of an access token.
|
||||||
|
*/
|
||||||
|
public String getRefreshToken(){
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a <code>LocalDateTime</code> which represents the latest point in time when the access token is still valid.
|
||||||
|
* @return A <code>LocalDateTime</code> representing the latest point in time of access token validity
|
||||||
|
*/
|
||||||
|
public LocalDateTime getValidUntil(){
|
||||||
|
return validUntil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the saved access token is still valid for use in calls, for example to the Spotify Web API services.
|
||||||
|
* @return true if the access token is still valid for use, false if not.
|
||||||
|
*/
|
||||||
|
public boolean isValid(){
|
||||||
|
return LocalDateTime.now(Clock.systemDefaultZone()).isBefore(getValidUntil());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the access token. If a new refresh token is provided it will be saved as well.
|
||||||
|
* @param cred The <code>AuthorizationCodeCredentials</code> to be saved. Recommended for use with recently (last few seconds) generated Credentials
|
||||||
|
*/
|
||||||
|
public void refreshCredentials(AuthorizationCodeCredentials cred){
|
||||||
|
this.accessToken = cred.getAccessToken();
|
||||||
|
if(Objects.nonNull(cred.getRefreshToken())) this.refreshToken = cred.getRefreshToken();
|
||||||
|
this.validUntil = LocalDateTime.now(Clock.systemDefaultZone()).plusSeconds(cred.getExpiresIn());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
package de.b00tload.tools.lastfmtospotifyplaylist.util;
|
package de.b00tload.tools.lastfmtospotifyplaylist.util;
|
||||||
|
|
||||||
import se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import static de.b00tload.tools.lastfmtospotifyplaylist.LastFMToSpotify.USER_HOME;
|
import static de.b00tload.tools.lastfmtospotifyplaylist.LastFMToSpotify.USER_HOME;
|
||||||
@@ -10,23 +8,23 @@ import static de.b00tload.tools.lastfmtospotifyplaylist.LastFMToSpotify.configur
|
|||||||
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>
|
* Manages saving a <code>de.b00tload.tools.lastfmtospotifyplaylist.util.SpotifyCredentials</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
|
* @param cred The <code>de.b00tload.tools.lastfmtospotifyplaylist.util.SpotifyCredentials</code> to be saved
|
||||||
*/
|
*/
|
||||||
public static void saveTokens(AuthorizationCodeCredentials cred) {
|
public static void saveTokens(SpotifyCredentials 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>
|
* Manages retrieving a <code>de.b00tload.tools.lastfmtospotifyplaylist.util.SpotifyCredentials</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>
|
* @return The retrieved <code>de.b00tload.tools.lastfmtospotifyplaylist.util.SpotifyCredentials</code>
|
||||||
*/
|
*/
|
||||||
public static AuthorizationCodeCredentials fetchTokens() {
|
public static SpotifyCredentials fetchTokens() {
|
||||||
return (AuthorizationCodeCredentials) CryptoHelper.deserializeEncrypted(Path.of(USER_HOME, "/.lfm2s/spotify.lfm2scred"), CryptoHelper.createKeyFromPassword(configuration.get("cache.crypto")));
|
return (SpotifyCredentials) 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
|
* Checks whether the saved SpotifyCredentials at "~/.lfm2s/spotify.lfm2scred" exist
|
||||||
* @return true if file exists, false if not
|
* @return true if file exists, false if not
|
||||||
*/
|
*/
|
||||||
public static boolean existsTokens(){
|
public static boolean existsTokens(){
|
||||||
|
|||||||
Reference in New Issue
Block a user