summaryrefslogtreecommitdiff
path: root/plugins/shotwell-publishing/FlickrPublishing.vala
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/shotwell-publishing/FlickrPublishing.vala')
-rw-r--r--plugins/shotwell-publishing/FlickrPublishing.vala427
1 files changed, 49 insertions, 378 deletions
diff --git a/plugins/shotwell-publishing/FlickrPublishing.vala b/plugins/shotwell-publishing/FlickrPublishing.vala
index 1702288..24b2b61 100644
--- a/plugins/shotwell-publishing/FlickrPublishing.vala
+++ b/plugins/shotwell-publishing/FlickrPublishing.vala
@@ -56,13 +56,7 @@ public class FlickrService : Object, Spit.Pluggable, Spit.Publishing.Service {
namespace Publishing.Flickr {
internal const string SERVICE_NAME = "Flickr";
-internal const string SERVICE_WELCOME_MESSAGE =
- _("You are not currently logged into Flickr.\n\nClick Log in to log into Flickr in your Web browser. You will have to authorize Shotwell Connect to link to your Flickr account.");
-internal const string RESTART_ERROR_MESSAGE =
- _("You have already logged in and out of Flickr during this Shotwell session.\nTo continue publishing to Flickr, quit and restart Shotwell, then try publishing again.");
internal const string ENDPOINT_URL = "https://api.flickr.com/services/rest";
-internal const string API_KEY = "60dd96d4a2ad04888b09c9e18d82c26f";
-internal const string API_SECRET = "d0960565e03547c1";
internal const int ORIGINAL_SIZE = -1;
internal const string EXPIRED_SESSION_ERROR_CODE = "98";
internal const string ENCODE_RFC_3986_EXTRA = "!*'();:@&=+$,/?%#[] \\";
@@ -104,168 +98,63 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
private bool was_started = false;
private Session session = null;
private PublishingOptionsPane publishing_options_pane = null;
+ private Spit.Publishing.Authenticator authenticator = null;
private PublishingParameters parameters = null;
public FlickrPublisher(Spit.Publishing.Service service,
- Spit.Publishing.PluginHost host) {
+ Spit.Publishing.PluginHost host) {
debug("FlickrPublisher instantiated.");
this.service = service;
this.host = host;
this.session = new Session();
this.parameters = new PublishingParameters();
-
- session.authenticated.connect(on_session_authenticated);
+ this.authenticator = Publishing.Authenticator.Factory.get_instance().create("flickr", host);
+
+ this.authenticator.authenticated.connect(on_session_authenticated);
}
~FlickrPublisher() {
- session.authenticated.disconnect(on_session_authenticated);
- }
-
- private void invalidate_persistent_session() {
- set_persistent_access_phase_token("");
- set_persistent_access_phase_token_secret("");
- set_persistent_access_phase_username("");
- }
-
- private bool is_persistent_session_valid() {
- return (get_persistent_access_phase_username() != null &&
- get_persistent_access_phase_token() != null &&
- get_persistent_access_phase_token_secret() != null);
- }
-
- private string? get_persistent_access_phase_username() {
- return host.get_config_string("access_phase_username", null);
- }
-
- private void set_persistent_access_phase_username(string username) {
- host.set_config_string("access_phase_username", username);
+ this.authenticator.authenticated.disconnect(on_session_authenticated);
}
- private string? get_persistent_access_phase_token() {
- return host.get_config_string("access_phase_token", null);
- }
-
- private void set_persistent_access_phase_token(string token) {
- host.set_config_string("access_phase_token", token);
- }
-
- private string? get_persistent_access_phase_token_secret() {
- return host.get_config_string("access_phase_token_secret", null);
- }
-
- private void set_persistent_access_phase_token_secret(string secret) {
- host.set_config_string("access_phase_token_secret", secret);
+ public Spit.Publishing.Authenticator get_authenticator() {
+ return this.authenticator;
}
private bool get_persistent_strip_metadata() {
return host.get_config_bool("strip_metadata", false);
}
-
+
private void set_persistent_strip_metadata(bool strip_metadata) {
host.set_config_bool("strip_metadata", strip_metadata);
- }
-
- private void on_welcome_pane_login_clicked() {
- if (!running)
- return;
-
- debug("EVENT: user clicked 'Login' button in the welcome pane");
-
- do_run_authentication_request_transaction();
}
- private void on_auth_request_txn_completed(Publishing.RESTSupport.Transaction txn) {
- txn.completed.disconnect(on_auth_request_txn_completed);
- txn.network_error.disconnect(on_auth_request_txn_error);
-
- if (!is_running())
- return;
-
- debug("EVENT: OAuth authentication request transaction completed; response = '%s'",
- txn.get_response());
-
- do_parse_token_info_from_auth_request(txn.get_response());
- }
-
- private void on_auth_request_txn_error(Publishing.RESTSupport.Transaction txn,
- Spit.Publishing.PublishingError err) {
- txn.completed.disconnect(on_auth_request_txn_completed);
- txn.network_error.disconnect(on_auth_request_txn_error);
-
- if (!is_running())
- return;
-
- debug("EVENT: OAuth authentication request transaction caused a network error");
- host.post_error(err);
- }
-
- private void on_authentication_token_available(string token, string token_secret) {
- debug("EVENT: OAuth authentication token (%s) and token secret (%s) available",
- token, token_secret);
-
- session.set_request_phase_credentials(token, token_secret);
-
- do_launch_system_browser(token);
- }
-
- private void on_system_browser_launched() {
- if (!is_running())
- return;
-
- debug("EVENT: system browser launched.");
-
- do_show_pin_entry_pane();
- }
-
- private void on_pin_entry_proceed(PinEntryPane sender, string pin) {
- sender.proceed.disconnect(on_pin_entry_proceed);
-
+ private void on_session_authenticated() {
if (!is_running())
return;
- debug("EVENT: user clicked 'Continue' in PIN entry pane.");
-
- do_verify_pin(pin);
- }
+ debug("EVENT: a fully authenticated session has become available");
- private void on_access_token_fetch_txn_completed(Publishing.RESTSupport.Transaction txn) {
- txn.completed.disconnect(on_access_token_fetch_txn_completed);
- txn.network_error.disconnect(on_access_token_fetch_error);
-
- if (!is_running())
- return;
-
- debug("EVENT: fetching OAuth access token over the network succeeded");
-
- do_extract_access_phase_credentials_from_reponse(txn.get_response());
- }
+ var params = this.authenticator.get_authentication_parameter();
+ Variant consumer_key = null;
+ Variant consumer_secret = null;
+ Variant auth_token = null;
+ Variant auth_token_secret = null;
+ Variant username = null;
- private void on_access_token_fetch_error(Publishing.RESTSupport.Transaction txn,
- Spit.Publishing.PublishingError err) {
- txn.completed.disconnect(on_access_token_fetch_txn_completed);
- txn.network_error.disconnect(on_access_token_fetch_error);
-
- if (!is_running())
- return;
+ params.lookup_extended("ConsumerKey", null, out consumer_key);
+ params.lookup_extended("ConsumerSecret", null, out consumer_secret);
+ session.set_api_credentials(consumer_key.get_string(), consumer_secret.get_string());
- debug("EVENT: fetching OAuth access token over the network caused an error.");
-
- host.post_error(err);
- }
-
- private void on_session_authenticated() {
- if (!is_running())
- return;
+ params.lookup_extended("AuthToken", null, out auth_token);
+ params.lookup_extended("AuthTokenSecret", null, out auth_token_secret);
+ params.lookup_extended("Username", null, out username);
+ session.set_access_phase_credentials(auth_token.get_string(),
+ auth_token_secret.get_string(), username.get_string());
- debug("EVENT: a fully authenticated session has become available");
-
parameters.username = session.get_username();
-
- set_persistent_access_phase_token(session.get_access_phase_token());
- set_persistent_access_phase_token_secret(session.get_access_phase_token_secret());
- set_persistent_access_phase_username(session.get_username());
-
+
do_fetch_account_info();
}
@@ -360,126 +249,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
host.post_error(err);
}
- private void do_show_login_welcome_pane() {
- debug("ACTION: installing login welcome pane");
-
- host.set_service_locked(false);
- host.install_welcome_pane(SERVICE_WELCOME_MESSAGE, on_welcome_pane_login_clicked);
- }
-
- private void do_run_authentication_request_transaction() {
- debug("ACTION: running authentication request transaction");
-
- host.set_service_locked(true);
- host.install_static_message_pane(_("Preparing for login…"));
-
- AuthenticationRequestTransaction txn = new AuthenticationRequestTransaction(session);
- txn.completed.connect(on_auth_request_txn_completed);
- txn.network_error.connect(on_auth_request_txn_error);
-
- try {
- txn.execute();
- } catch (Spit.Publishing.PublishingError err) {
- host.post_error(err);
- }
- }
-
- private void do_parse_token_info_from_auth_request(string response) {
- debug("ACTION: parsing authorization request response '%s' into token and secret", response);
-
- string? oauth_token = null;
- string? oauth_token_secret = null;
-
- var data = Soup.Form.decode(response);
- data.lookup_extended("oauth_token", null, out oauth_token);
- data.lookup_extended("oauth_token_secret", null, out oauth_token_secret);
-
- if (oauth_token == null || oauth_token_secret == null)
- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE(
- "'%s' isn't a valid response to an OAuth authentication request", response));
-
-
- on_authentication_token_available(oauth_token, oauth_token_secret);
- }
-
- private void do_launch_system_browser(string token) {
- string login_uri = "https://www.flickr.com/services/oauth/authorize?oauth_token=" + token +
- "&perms=write";
-
- debug("ACTION: launching system browser with uri = '%s'", login_uri);
-
- try {
- Process.spawn_command_line_async("xdg-open " + login_uri);
- } catch (SpawnError e) {
- host.post_error(new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR(
- "couldn't launch system web browser to complete Flickr login"));
- return;
- }
-
- on_system_browser_launched();
- }
-
- private void do_show_pin_entry_pane() {
- debug("ACTION: showing PIN entry pane");
-
- Gtk.Builder builder = new Gtk.Builder();
-
- try {
- builder.add_from_resource (Resources.RESOURCE_PATH + "/" +
- "flickr_pin_entry_pane.ui");
- } catch (Error e) {
- warning("Could not parse UI file! Error: %s.", e.message);
- host.post_error(
- new Spit.Publishing.PublishingError.LOCAL_FILE_ERROR(
- _("A file required for publishing is unavailable. Publishing to Flickr can’t continue.")));
- return;
- }
-
- PinEntryPane pin_entry_pane = new PinEntryPane(builder);
- pin_entry_pane.proceed.connect(on_pin_entry_proceed);
- host.install_dialog_pane(pin_entry_pane);
- }
-
- private void do_verify_pin(string pin) {
- debug("ACTION: validating authorization PIN %s", pin);
-
- host.set_service_locked(true);
- host.install_static_message_pane(_("Verifying authorization…"));
-
- AccessTokenFetchTransaction txn = new AccessTokenFetchTransaction(session, pin);
- txn.completed.connect(on_access_token_fetch_txn_completed);
- txn.network_error.connect(on_access_token_fetch_error);
-
- try {
- txn.execute();
- } catch (Spit.Publishing.PublishingError err) {
- host.post_error(err);
- }
- }
-
- private void do_extract_access_phase_credentials_from_reponse(string response) {
- debug("ACTION: extracting access phase credentials from '%s'", response);
-
- string? token = null;
- string? token_secret = null;
- string? username = null;
-
- var data = Soup.Form.decode(response);
- data.lookup_extended("oauth_token", null, out token);
- data.lookup_extended("oauth_token_secret", null, out token_secret);
- data.lookup_extended("username", null, out username);
-
- debug("access phase credentials: { token = '%s'; token_secret = '%s'; username = '%s' }",
- token, token_secret, username);
-
- if (token == null || token_secret == null || username == null)
- host.post_error(new Spit.Publishing.PublishingError.MALFORMED_RESPONSE("expected " +
- "access phase credentials to contain token, token secret, and username but at " +
- "least one of these is absent"));
-
- session.set_access_phase_credentials(token, token_secret, username);
- }
-
private void do_fetch_account_info() {
debug("ACTION: running network transaction to fetch account information");
@@ -544,8 +313,9 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
private void do_logout() {
debug("ACTION: logging user out, deauthenticating session, and erasing stored credentials");
- session.deauthenticate();
- invalidate_persistent_session();
+ if (authenticator.can_logout()) {
+ authenticator.logout();
+ }
running = false;
@@ -650,16 +420,7 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
running = true;
was_started = true;
- if (is_persistent_session_valid()) {
- debug("attempt start: a persistent session is available; using it");
-
- session.authenticate_from_persistent_credentials(get_persistent_access_phase_token(),
- get_persistent_access_phase_token_secret(), get_persistent_access_phase_username());
- } else {
- debug("attempt start: no persistent session available; showing login welcome pane");
-
- do_show_login_welcome_pane();
- }
+ authenticator.authenticate();
}
public void start() {
@@ -684,60 +445,6 @@ public class FlickrPublisher : Spit.Publishing.Publisher, GLib.Object {
}
}
-internal class PinEntryPane : Spit.Publishing.DialogPane, GLib.Object {
- private Gtk.Box pane_widget = null;
- private Gtk.Button continue_button = null;
- private Gtk.Entry pin_entry = null;
- private Gtk.Label pin_entry_caption = null;
- private Gtk.Label explanatory_text = null;
- private Gtk.Builder builder = null;
-
- public signal void proceed(PinEntryPane sender, string authorization_pin);
-
- public PinEntryPane(Gtk.Builder builder) {
- this.builder = builder;
- assert(builder != null);
- assert(builder.get_objects().length() > 0);
-
- explanatory_text = builder.get_object("explanatory_text") as Gtk.Label;
- pin_entry_caption = builder.get_object("pin_entry_caption") as Gtk.Label;
- pin_entry = builder.get_object("pin_entry") as Gtk.Entry;
- continue_button = builder.get_object("continue_button") as Gtk.Button;
-
- pane_widget = builder.get_object("pane_widget") as Gtk.Box;
-
- pane_widget.show_all();
-
- on_pin_entry_contents_changed();
- }
-
- private void on_continue_clicked() {
- proceed(this, pin_entry.get_text());
- }
-
- private void on_pin_entry_contents_changed() {
- continue_button.set_sensitive(pin_entry.text_length > 0);
- }
-
- public Gtk.Widget get_widget() {
- return pane_widget;
- }
-
- public Spit.Publishing.DialogPane.GeometryOptions get_preferred_geometry() {
- return Spit.Publishing.DialogPane.GeometryOptions.NONE;
- }
-
- public void on_pane_installed() {
- continue_button.clicked.connect(on_continue_clicked);
- pin_entry.changed.connect(on_pin_entry_contents_changed);
- }
-
- public void on_pane_uninstalled() {
- continue_button.clicked.disconnect(on_continue_clicked);
- pin_entry.changed.disconnect(on_pin_entry_contents_changed);
- }
-}
-
internal class Transaction : Publishing.RESTSupport.Transaction {
public Transaction(Session session, Publishing.RESTSupport.HttpMethod method =
Publishing.RESTSupport.HttpMethod.POST) {
@@ -748,7 +455,7 @@ internal class Transaction : Publishing.RESTSupport.Transaction {
add_argument("oauth_version", "1.0");
add_argument("oauth_callback", "oob");
add_argument("oauth_timestamp", session.get_oauth_timestamp());
- add_argument("oauth_consumer_key", API_KEY);
+ add_argument("oauth_consumer_key", session.get_consumer_key());
}
public Transaction.with_uri(Session session, string uri,
@@ -760,7 +467,7 @@ internal class Transaction : Publishing.RESTSupport.Transaction {
add_argument("oauth_version", "1.0");
add_argument("oauth_callback", "oob");
add_argument("oauth_timestamp", session.get_oauth_timestamp());
- add_argument("oauth_consumer_key", API_KEY);
+ add_argument("oauth_consumer_key", session.get_consumer_key());
}
public override void execute() throws Spit.Publishing.PublishingError {
@@ -818,22 +525,6 @@ internal class Transaction : Publishing.RESTSupport.Transaction {
}
}
-internal class AuthenticationRequestTransaction : Transaction {
- public AuthenticationRequestTransaction(Session session) {
- base.with_uri(session, "https://www.flickr.com/services/oauth/request_token",
- Publishing.RESTSupport.HttpMethod.GET);
- }
-}
-
-internal class AccessTokenFetchTransaction : Transaction {
- public AccessTokenFetchTransaction(Session session, string user_verifier) {
- base.with_uri(session, "https://www.flickr.com/services/oauth/access_token",
- Publishing.RESTSupport.HttpMethod.GET);
- add_argument("oauth_verifier", user_verifier);
- add_argument("oauth_token", session.get_request_phase_token());
- }
-}
-
internal class AccountInfoFetchTransaction : Transaction {
public AccountInfoFetchTransaction(Session session) {
base(session, Publishing.RESTSupport.HttpMethod.GET);
@@ -860,7 +551,7 @@ private class UploadTransaction : Publishing.RESTSupport.UploadTransaction {
add_authorization_header_field("oauth_version", "1.0");
add_authorization_header_field("oauth_callback", "oob");
add_authorization_header_field("oauth_timestamp", session.get_oauth_timestamp());
- add_authorization_header_field("oauth_consumer_key", API_KEY);
+ add_authorization_header_field("oauth_consumer_key", session.get_consumer_key());
add_authorization_header_field("oauth_token", session.get_access_phase_token());
add_argument("is_public", ("%d".printf(parameters.visibility_specification.everyone_level)));
@@ -920,11 +611,11 @@ private class UploadTransaction : Publishing.RESTSupport.UploadTransaction {
}
internal class Session : Publishing.RESTSupport.Session {
- private string? request_phase_token = null;
- private string? request_phase_token_secret = null;
private string? access_phase_token = null;
private string? access_phase_token_secret = null;
private string? username = null;
+ private string? consumer_key = null;
+ private string? consumer_secret = null;
public Session() {
base(ENDPOINT_URL);
@@ -935,19 +626,9 @@ internal class Session : Publishing.RESTSupport.Session {
username != null);
}
- public void authenticate_from_persistent_credentials(string token, string secret,
- string username) {
- this.access_phase_token = token;
- this.access_phase_token_secret = secret;
- this.username = username;
-
- authenticated();
- }
-
- public void deauthenticate() {
- access_phase_token = null;
- access_phase_token_secret = null;
- username = null;
+ public void set_api_credentials(string consumer_key, string consumer_secret) {
+ this.consumer_key = consumer_key;
+ this.consumer_secret = consumer_secret;
}
public void sign_transaction(Publishing.RESTSupport.Transaction txn) {
@@ -984,16 +665,12 @@ internal class Session : Publishing.RESTSupport.Session {
if (access_phase_token_secret != null) {
debug("access phase token secret available; using it as signing key");
- signing_key = API_SECRET + "&" + access_phase_token_secret;
- } else if (request_phase_token_secret != null) {
- debug("request phase token secret available; using it as signing key");
-
- signing_key = API_SECRET + "&" + request_phase_token_secret;
+ signing_key = consumer_secret + "&" + access_phase_token_secret;
} else {
debug("neither access phase nor request phase token secrets available; using API " +
"key as signing key");
- signing_key = API_SECRET + "&";
+ signing_key = consumer_secret + "&";
}
string signature_base_string = http_method + "&" + Soup.URI.encode(
@@ -1016,11 +693,6 @@ internal class Session : Publishing.RESTSupport.Session {
txn.add_argument("oauth_signature", signature);
}
- public void set_request_phase_credentials(string token, string secret) {
- this.request_phase_token = token;
- this.request_phase_token_secret = secret;
- }
-
public void set_access_phase_credentials(string token, string secret, string username) {
this.access_phase_token = token;
this.access_phase_token_secret = secret;
@@ -1040,22 +712,17 @@ internal class Session : Publishing.RESTSupport.Session {
public string get_oauth_timestamp() {
return GLib.get_real_time().to_string().substring(0, 10);
}
-
- public string get_request_phase_token() {
- assert(request_phase_token != null);
- return request_phase_token;
+
+ public string get_consumer_key() {
+ assert(consumer_key != null);
+ return consumer_key;
}
-
+
public string get_access_phase_token() {
assert(access_phase_token != null);
return access_phase_token;
}
- public string get_access_phase_token_secret() {
- assert(access_phase_token_secret != null);
- return access_phase_token_secret;
- }
-
public string get_username() {
assert(is_authenticated());
return username;
@@ -1119,6 +786,10 @@ internal class PublishingOptionsPane : Spit.Publishing.DialogPane, GLib.Object {
size_label = (Gtk.Label) this.builder.get_object("size_label");
strip_metadata_check = (Gtk.CheckButton) this.builder.get_object("strip_metadata_check");
+ if (!publisher.get_authenticator().can_logout()) {
+ logout_button.parent.remove(logout_button);
+ }
+
this.parameters = parameters;
this.publisher = publisher;
this.media_type = media_type;