src/moonshot-id.c
src/moonshot-idcard-widget.c
src/moonshot-idcard-store.c
+src/moonshot-identity-dialog.c
src/moonshot-identity-request.c
src/moonshot-identity-management-view.c
src/moonshot-identity-manager-app.c
src/moonshot-provisioning-common-new.vala
src/moonshot-provisioning-common.c
src/moonshot-server.c
+src/moonshot-settings.c
+src/moonshot-trust-anchor-dialog.c
src/moonshot-utils.c
+src/moonshot-warning-dialog.c
src/moonshot-webp-parser.c
src/moonshot-window.c
src/msrpc-client.c
src/moonshot-keyring-store.vala \
src/moonshot-idcard-store.vala \
src/moonshot-id.vala \
- src/moonshot-add-dialog.vala \
+ src/moonshot-identity-dialog.vala \
src/moonshot-idcard-widget.vala \
src/moonshot-custom-vbox.vala \
src/moonshot-identities-manager.vala \
src/moonshot-identity-request.vala \
src/moonshot-server.vala \
+ src/moonshot-settings.vala \
src/moonshot-password-dialog.vala \
src/moonshot-provisioning-common.vala \
+ src/moonshot-trust-anchor-dialog.vala \
src/moonshot-utils.vala \
src/moonshot-futils.c \
- src/moonshot-logger.vala
+ src/moonshot-crypto-utils.c \
+ src/moonshot-logger.vala \
+ src/moonshot-warning-dialog.vala
src_moonshot_webp_SOURCES = \
+ src/moonshot-crypto-utils.c \
src/moonshot-webp-parser.vala \
src/moonshot-provisioning-common.vala \
src/moonshot-id.vala \
src_moonshot_LDADD = $(moonshot_LIBS)
src_moonshot_LDFLAGS = -g -O0 $(MOONSHOT_LOG_LIBS)
-src_moonshot_webp_VALAFLAGS = --vapidir=$(top_srcdir)/libmoonshot --pkg libmoonshot $(AM_VALAFLAGS)
+src_moonshot_webp_VALAFLAGS = --vapidir=$(top_srcdir)/libmoonshot --pkg $(GEE_VERSION) --pkg libmoonshot $(AM_VALAFLAGS)
src_moonshot_webp_CPPFLAGS = $(moonshot_CFLAGS) $(AM_CPPFLAGS)
src_moonshot_webp_LDADD = $(moonshot_LIBS) ${top_builddir}/libmoonshot/libmoonshot.la
src_moonshot_webp_LDFLAGS = $(MOONSHOT_LOG_LIBS)
AM_CPPFLAGS += -I/usr/include/gnome-keyring-1
AM_VALAFLAGS += --pkg moonshot-gnome-keyring --define=GNOME_KEYRING
-src_moonshot_LDFLAGS += -lgnome-keyring
-src_moonshot_webp_LDFLAGS += -lgnome-keyring
+src_moonshot_LDFLAGS += -lgnome-keyring -lcrypto
+src_moonshot_webp_LDFLAGS += -lgnome-keyring -lcrypto
## Installing mime type data
mimedir = $(datadir)/mime/packages
AC_PREREQ([2.63])
AC_INIT([Moonshot-ui],
- [0.7.2],
+ [1.0.0],
[moonshot-community@jiscmail.ac.uk],
[moonshot-ui],
[http://www.project-moonshot.org/])
atk >= 1.20
glib-2.0 >= 2.22
gobject-2.0 >= 2.22
+ libssl
$GTK_VERSION
$GEE_VERSION
$SERVER_IPC_MODULE
G_TYPE_INVALID);
g_object_unref (dbus_proxy);
+ g_free(rules_patterns_strv);
+ g_free(rules_always_confirm_strv);
+ g_free(services_strv);
if (g_error != NULL) {
*error = moonshot_error_new (MOONSHOT_ERROR_IPC_ERROR,
# List of source files which contain translatable strings.
+src/moonshot-idcard-widget.vala
+src/moonshot-identities-manager.vala
+src/moonshot-identity-dialog.vala
src/moonshot-identity-management-view.vala
+src/moonshot-identity-manager-app.vala
+src/moonshot-password-dialog.vala
+src/moonshot-server.vala
+src/moonshot-trust-anchor-dialog.vala
+src/moonshot-warning-dialog.vala
+src/moonshot-webp-parser.vala
+++ /dev/null
-/*
- * Copyright (c) 2011-2014, JANET(UK)
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * 3. Neither the name of JANET(UK) nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
-*/
-using Gtk;
-
-
-// Defined here as workaround for emacs vala-mode indentation failure.
-#if VALA_0_12
-static const string CANCEL = Stock.CANCEL;
-#else
-static const string CANCEL = STOCK_CANCEL;
-#endif
-
-
-class AddIdentityDialog : Dialog
-{
- static const string displayname_labeltext = _("Display Name");
- static const string issuer_labeltext = _("Issuer");
- static const string username_labeltext = _("Username");
- static const string password_labeltext = _("Password");
- private Entry displayname_entry;
- private Label displayname_label;
- private Entry issuer_entry;
- private Label issuer_label;
- private Entry username_entry;
- private Label username_label;
- private Entry password_entry;
- private Label password_label;
- private CheckButton remember_checkbutton;
- private Label message_label;
- public bool complete;
-
- public string display_name {
- get { return displayname_entry.get_text(); }
- }
-
- public string issuer {
- get { return issuer_entry.get_text(); }
- }
-
- public string username {
- get { return username_entry.get_text(); }
- }
-
- public string password {
- get { return password_entry.get_text(); }
- }
-
- public bool store_password {
- get { return remember_checkbutton.active; }
- }
-
- public AddIdentityDialog()
- {
- this.set_title(_("Add ID Card"));
- this.set_modal(true);
-
- this.add_buttons(_("Add ID Card"), ResponseType.OK,
- CANCEL, ResponseType.CANCEL);
- var content_area = this.get_content_area();
- ((Box) content_area).set_spacing(12);
-
- displayname_label = new Label(@"$displayname_labeltext:");
- displayname_label.set_alignment(1,(float) 0.5);
- displayname_entry = new Entry();
- issuer_label = new Label(@"$issuer_labeltext:");
- issuer_label.set_alignment(1,(float) 0.5);
- this.issuer_entry = new Entry();
- username_label = new Label(@"$username_labeltext:");
- username_label.set_alignment(1,(float) 0.5);
- this.username_entry = new Entry();
- password_label = new Label(@"$password_labeltext:");
- password_label.set_alignment(1,(float) 0.5);
- this.password_entry = new Entry();
- password_entry.set_invisible_char('*');
- password_entry.set_visibility(false);
- this.remember_checkbutton = new CheckButton.with_label(_("Remember password"));
- this.message_label = new Label("");
- message_label.set_visible(false);
-
- set_atk_relation(displayname_label, displayname_entry, Atk.RelationType.LABEL_FOR);
- set_atk_relation(issuer_label, issuer_entry, Atk.RelationType.LABEL_FOR);
- set_atk_relation(username_label, username_entry, Atk.RelationType.LABEL_FOR);
- set_atk_relation(password_entry, password_entry, Atk.RelationType.LABEL_FOR);
-
- var table = new Table(6, 2, false);
- table.set_col_spacings(10);
- table.set_row_spacings(10);
-
- table.attach_defaults(message_label, 0, 2, 0, 1);
- table.attach_defaults(displayname_label, 0, 1, 1, 2);
- table.attach_defaults(displayname_entry, 1, 2, 1, 2);
- table.attach_defaults(issuer_label, 0, 1, 2, 3);
- table.attach_defaults(issuer_entry, 1, 2, 2, 3);
- table.attach_defaults(username_label, 0, 1, 3, 4);
- table.attach_defaults(username_entry, 1, 2, 3, 4);
- table.attach_defaults(password_label, 0, 1, 4, 5);
- table.attach_defaults(password_entry, 1, 2, 4, 5);
- table.attach_defaults(remember_checkbutton, 1, 2, 5, 6);
-
- this.response.connect(on_response);
- var vbox = new VBox(false, 0);
- vbox.set_border_width(6);
- vbox.pack_start(table, false, false, 0);
-
- ((Container) content_area).add(vbox);
-
- this.set_border_width(6);
- this.set_resizable(false);
- this.show_all();
- }
-
- private static string update_preamble(string preamble)
- {
- if (preamble == "")
- return _("Missing required field: ");
- return _("Missing required fields: ");
- }
-
- private static string update_message(string old_message, string new_item)
- {
- string message;
- if (old_message == "")
- message = new_item;
- else
- message = old_message + ", " + new_item;
- return message;
- }
-
- private static void check_field(string field, Label label, string fieldname, ref string preamble, ref string message)
- {
- if (field != "") {
- label.set_markup(@"$fieldname:");
- return;
- }
- label.set_markup(@"<span foreground=\"red\">$fieldname:</span>");
- preamble = update_preamble(preamble);
- message = update_message(message, fieldname);
- }
-
- private bool check_fields()
- {
- string preamble = "";
- string message = "";
- string password_test = store_password ? password : "not required";
- check_field(display_name, displayname_label, displayname_labeltext, ref preamble, ref message);
- check_field(issuer, issuer_label, issuer_labeltext, ref preamble, ref message);
- check_field(username, username_label, username_labeltext, ref preamble, ref message);
- check_field(password_test, password_label, password_labeltext, ref preamble, ref message);
- if (message != "") {
- message_label.set_visible(true);
- message_label.set_markup(@"<span foreground=\"red\">$preamble$message</span>");
- return false;
- }
- return true;
- }
-
- private void on_response(Dialog source, int response_id)
- {
- switch (response_id) {
- case ResponseType.OK:
- complete = check_fields();
- break;
- case ResponseType.CANCEL:
- complete = true;
- break;
- }
- }
-
- private void set_atk_relation(Widget widget, Widget target_widget, Atk.RelationType relationship)
- {
- var atk_widget = widget.get_accessible();
- var atk_target_widget = target_widget.get_accessible();
-
- atk_widget.add_relationship(relationship, atk_target_widget);
- }
-}
--- /dev/null
+#include <string.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+
+#include <stdio.h>
+
+char* get_cert_valid_before(const unsigned char* buf, int len, char* datebuf, int datebuf_len)
+{
+ datebuf[0]='\0';
+
+ unsigned char *p = (unsigned char*) buf;
+ X509* x = d2i_X509(NULL, &p, len);
+ if (x == NULL) {
+ return "Error calling d2i_X509()!";
+ }
+
+ BIO* out_bio = BIO_new(BIO_s_mem());
+ ASN1_TIME* time = X509_get_notAfter(x);
+
+ if (ASN1_TIME_print(out_bio, time)) {
+ int write = BIO_read(out_bio, datebuf, datebuf_len - 1);
+ datebuf[write]='\0';
+ }
+
+ datebuf[datebuf_len - 1] = '\0';
+ BIO_free(out_bio);
+ X509_free(x);
+ return "";
+}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
class CustomVBox : VBox
{
- public IdCardWidget current_idcard { get; set; default = null; }
+ static MoonshotLogger logger = get_logger("CustomVBox");
private IdentityManagerView main_window;
-
+ int next_pos = 0;
+
public CustomVBox(IdentityManagerView window, bool homogeneous, int spacing)
{
main_window = window;
set_spacing(spacing);
}
- public void receive_expanded_event(IdCardWidget id_card_widget)
+ internal void receive_expanded_event(IdCardWidget id_card_widget)
{
var list = get_children();
foreach (Widget id_card in list)
if (id_card != id_card_widget)
((IdCardWidget) id_card).collapse();
}
- current_idcard = id_card_widget;
- if (current_idcard != null && main_window.request_queue.length > 0)
- current_idcard.send_button.set_sensitive(true);
+ check_resize();
+ }
+
+ internal void receive_collapsed_event(IdCardWidget id_card_widget)
+ {
check_resize();
}
public void add_id_card_widget(IdCardWidget id_card_widget)
{
pack_start(id_card_widget, false, false);
+ id_card_widget.position = next_pos++;
}
- public void remove_id_card_widget(IdCardWidget id_card_widget)
- {
- remove(id_card_widget);
+ public IdCardWidget? find_idcard_widget(IdCard id_card) {
+ foreach (var w in get_children()) {
+ IdCardWidget widget = (IdCardWidget) w;
+ if (widget.id_card.nai == id_card.nai) {
+ return widget;
+ }
+ }
+ return null;
}
+
+ internal void clear()
+ {
+ logger.trace("clear");
+
+ var children = get_children();
+ foreach (var id_card_widget in children) {
+ remove(id_card_widget);
+ }
+
+ next_pos = 0;
+ }
+
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
+using Gee;
+
+extern char* get_cert_valid_before(uchar* inbuf, int inlen, char* outbuf, int outlen);
+
+
+// A TrustAnchor object can be imported or installed via the API, but cannot
+// be modified by the user, other than being cleared. Hence the fields are read-only.
public class TrustAnchor : Object
{
- public string ca_cert {get; set; default = "";}
- public string subject {get; set; default = "";}
- public string subject_alt {get; set; default = "";}
- public string server_cert {get; set; default = "";}
+ private static const string CERT_HEADER = "-----BEGIN CERTIFICATE-----";
+ private static const string CERT_FOOTER = "-----END CERTIFICATE-----";
+
+ public enum TrustAnchorType {
+ CA_CERT,
+ SERVER_CERT
+ }
+
+ private string _ca_cert = "";
+ private string _subject = "";
+ private string _subject_alt = "";
+ private string _server_cert = "";
+ private string _datetime_added = "";
+ public bool user_verified = false;
+
+ private static string fixup (string s) {
+ return (s == null ? "" : s.strip());
+ }
+
+ public TrustAnchor(string ca_cert, string server_cert, string subject, string subject_alt, bool user_verified) {
+ _ca_cert = fixup(ca_cert);
+ _server_cert = fixup(server_cert);
+ _subject = fixup(subject);
+ _subject_alt = fixup(subject_alt);
+ this.user_verified = user_verified;
+
+ // If we're reading from store, this will be overridden (see set_datetime_added)
+ _datetime_added = "";
+ }
+
+ public TrustAnchor.empty() {
+ }
+
+
+ public string ca_cert {
+ get {
+ return _ca_cert;
+ }
+ }
+
+ public string subject {
+ get {
+ return _subject;
+ }
+ }
+
+ public string subject_alt {
+ get {
+ return _subject_alt;
+ }
+ }
+
+
+ public string server_cert {
+ get {
+ return _server_cert;
+ }
+ }
+
+ public string datetime_added {
+ get {
+ return _datetime_added;
+ }
+ }
+
+ public bool is_empty() {
+ return ca_cert == "" && subject == "" && subject_alt == "" && server_cert == "";
+ }
+
+ public TrustAnchorType get_anchor_type() {
+ return server_cert == "" ? TrustAnchorType.CA_CERT : TrustAnchorType.SERVER_CERT;
+ }
+
+ internal void set_datetime_added(string datetime) {
+ _datetime_added = fixup(datetime);
+ }
+
+ internal static string format_datetime_now() {
+ DateTime now = new DateTime.now_utc();
+ string dt = now.format("%b %d %T %Y %Z");
+ return dt;
+ }
+
public int Compare(TrustAnchor other)
{
- if (this.ca_cert != other.ca_cert)
+ if (this.ca_cert != other.ca_cert) {
+ // IdCard.logger.trace("TrustAnchor.Compare: this.ca_cert='%s'; other.ca_cert='%s'".printf(this.ca_cert, other.ca_cert));
return 1;
- if (this.subject != other.subject)
+ }
+ if (this.subject != other.subject) {
+ // IdCard.logger.trace("TrustAnchor.Compare: this.subject='%s'; other.subject='%s'".printf(this.subject, other.subject));
return 1;
- if (this.subject_alt != other.subject_alt)
+ }
+ if (this.subject_alt != other.subject_alt) {
+ // IdCard.logger.trace("TrustAnchor.Compare: this.subject_alt='%s'; other.subject_alt='%s'".printf(this.subject_alt, other.subject_alt));
return 1;
- if (this.server_cert != other.server_cert)
+ }
+ if (this.server_cert != other.server_cert) {
+ // IdCard.logger.trace("TrustAnchor.Compare: this.server_cert=%s'; other.server_cert='%s'".printf(this.server_cert, other.server_cert));
return 1;
+ }
+
+ // Do not compare the user_verified and datetime_added fields; they are not essential.
+
return 0;
}
+
+ public string? get_expiration_date(out string? err_out=null)
+ {
+ if (&err_out != null) {
+ err_out = null;
+ }
+
+ if (this.ca_cert == "") {
+ if (&err_out != null) {
+ err_out = "Trust anchor does not have a ca_certificate";
+ return null;
+ }
+ }
+
+ string cert = this.ca_cert;
+ cert.chomp();
+
+ uchar[] binary = Base64.decode(cert);
+ IdCard.logger.trace("get_expiration_date: encoded length=%d; decoded length=%d".printf(cert.length, binary.length));
+
+ char buf[64];
+ string err = (string) get_cert_valid_before(binary, binary.length, buf, 64);
+ if (err != "") {
+ IdCard.logger.error(@"get_expiration_date: get_cert_valid_before returned '$err'");
+ if (&err_out != null) {
+ err_out = err;
+ }
+ return null;
+ }
+
+ string date = (string) buf;
+ IdCard.logger.trace(@"get_expiration_date: get_cert_valid_before returned '$date'");
+
+ return date;
+ }
}
+
public struct Rule
{
public string pattern;
public class IdCard : Object
{
+ internal static MoonshotLogger logger = get_logger("IdCard");
+
public const string NO_IDENTITY = "No Identity";
- private string _nai;
-
+ private string _username = "";
+ private string _issuer = "";
+
public string display_name { get; set; default = ""; }
- public string username { get; set; default = ""; }
+ public string username {
+ public get {
+ return _username;
+ }
+ public set {
+ _username = value;
+ update_nai();
+ }
+ }
+
+ public string issuer {
+ public get {
+ return _issuer;
+ }
+ public set {
+ _issuer = value;
+ update_nai();
+ }
+ }
+
+ private void update_nai() {
+ _nai = username + "@" + issuer;
+ }
+
#if GNOME_KEYRING
private unowned string _password;
public string password {
public string password { get; set; default = null; }
#endif
- public string issuer { get; set; default = ""; }
-
private Rule[] _rules = new Rule[0];
public Rule[] rules {
get {return _rules;}
internal set {_rules = value ?? new Rule[0] ;}
}
- private string[] _services = new string[0];
- public string[] services {
- get {return _services;}
- internal set {_services = value ?? new string[0] ;}
+ private ArrayList<string> _services = new ArrayList<string>();
+
+ internal ArrayList<string> services {
+ get {return _services;}
+ }
+
+ // Returns the list of services as a string, using the given separator.
+ internal string get_services_string(string sep) {
+ if (_services.is_empty) {
+ return "";
+ }
+
+ // ArrayList.to_array() seems to be unreliable -- it causes segfaults
+ // semi-randomly. (Possibly because it returns an unowned ref?)
+ // return string.joinv(sep, _services.to_array());
+ //
+ // This problem may be related to the one noted elsewhere as the
+ // "Centos vala array property bug".
+
+ string[] svcs = new string[_services.size];
+ for (int i = 0; i < _services.size; i++) {
+ svcs[i] = _services[i];
+ }
+
+ return string.joinv(sep, svcs);
}
+ internal void update_services(string[] services) {
+ _services.clear();
+
+ // Doesn't exist in older versions of libgee:
+ // _services.add_all_array(services);
+
+ if (services != null) {
+ foreach (string s in services) {
+ _services.add(s);
+ }
+ }
+ }
+
+ internal void update_services_from_list(ArrayList<string> services) {
+ if (services == this._services) {
+ // Don't try to update from self.
+ return;
+ }
+
+ _services.clear();
+
+ if (services != null) {
+ _services.add_all(services);
+ }
+ }
+
+
public bool temporary {get; set; default = false; }
- public TrustAnchor trust_anchor { get; set; default = new TrustAnchor (); }
+ private TrustAnchor _trust_anchor = new TrustAnchor.empty();
+ public TrustAnchor trust_anchor {
+ get {
+ return _trust_anchor;
+ }
+ }
+
+ // For use by storage implementations.
+ internal void set_trust_anchor_from_store(TrustAnchor ta) {
+ _trust_anchor = ta;
+ }
+
+ internal void clear_trust_anchor() {
+ _trust_anchor = new TrustAnchor.empty();
+ }
- public unowned string nai { get { _nai = username + "@" + issuer; return _nai;}}
+ public string nai { public get; private set;}
public bool store_password { get; set; default = false; }
- public bool IsNoIdentity()
+ public bool is_no_identity()
{
return (display_name == NO_IDENTITY);
}
if (CompareRules(this.rules, other.rules)!=0)
diff |= 1 << DiffFlags.RULES;
- if (CompareStringArray(this.services, other.services)!=0)
+ if (CompareStringArrayList(this._services, other._services)!=0)
diff |= 1 << DiffFlags.SERVICES;
if (this.trust_anchor.Compare(other.trust_anchor)!=0)
diff |= 1 << DiffFlags.TRUST_ANCHOR;
// stdout.printf("Diff Flags: %x\n", diff);
+ if (this.display_name == other.display_name && diff != 0) {
+ logger.trace("Compare: Two IDs with display_name '%s', but diff_flags=%0x".printf(this.display_name, diff));
+ }
return diff;
}
internal void add_rule(Rule rule) {
_rules += rule;
}
-
- internal void add_service(string service) {
- _services += service;
- }
}
public int CompareRules(Rule[] a, Rule[] b)
return 0;
}
-public int CompareStringArray(string[] a, string [] b)
+public int CompareStringArrayList(ArrayList<string> a, ArrayList<string> b)
{
- if (a.length != b.length) {
+ if (a.size != b.size) {
return 1;
}
- for (int i = 0; i < a.length; i++) {
+ for (int i = 0; i < a.size; i++) {
if (a[i] != b[i]) {
return 1;
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
public abstract IdCard? update_card(IdCard card);
public abstract StoreType get_store_type();
public abstract LinkedList<IdCard> get_card_list();
+
+ // Note that (at least right now) store_id_cards() will re-load the cards after saving them.
+ internal abstract void store_id_cards();
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
class IdCardWidget : Box
{
- public IdCard id_card { get; set; default = null; }
+ // static MoonshotLogger logger = get_logger("IdCardWidget");
+
+ private static const ShadowType ARROW_SHADOW = ShadowType.NONE;
+
+ private IdentityManagerView manager_view;
+ public IdCard id_card { get; set; default = null; }
private VBox main_vbox;
private HBox table;
- public Button delete_button { get; private set; default = null; }
- public Button details_button { get; private set; default = null; }
- public Button send_button { get; private set; default = null; }
- private HButtonBox hbutton_box;
private EventBox event_box;
+ private bool is_selected = false;
+ private Arrow arrow;
private Label label;
+ internal int _position = 0;
+ internal int position {
+ get {return _position;}
+ set {_position = value; set_idcard_color();}
+ }
+
public signal void expanded();
- public signal void remove_id();
- public signal void details_id();
- public signal void send_id();
+ public signal void collapsed();
- public void collapse()
+ internal void select()
{
- this.hbutton_box.set_visible(false);
+ expand();
+ this.expanded();
+ }
- set_idcard_color();
+ internal void unselect()
+ {
+ collapse();
+ this.collapsed();
}
public void expand()
{
- this.hbutton_box.set_visible(true);
+ is_selected = true;
+ update_id_card_label();
set_idcard_color();
- this.expanded();
+ arrow.set(ArrowType.DOWN, ARROW_SHADOW);
}
- private bool button_press_cb()
+ public void collapse()
{
- if (hbutton_box.get_visible())
- collapse();
- else
- expand();
-
- return false;
- }
+ is_selected = false;
+ update_id_card_label();
- private void delete_button_cb()
- {
- this.remove_id();
+ set_idcard_color();
+ arrow.set(ArrowType.RIGHT, ARROW_SHADOW);
}
- private void details_button_cb()
+ private bool button_press_cb()
{
- this.details_id();
- }
+ if (is_selected)
+ unselect();
+ else
+ select();
- private void send_button_cb()
- {
- this.send_id();
+ return false;
}
private void set_idcard_color()
{
var color = Gdk.Color();
- if (hbutton_box.get_visible() == false)
+ if (is_selected)
{
- color.red = 65535;
- color.green = 65535;
- color.blue = 65535;
+ color.red = 0xd9 << 8;
+ color.green = 0xf7 << 8;
+ color.blue = 65535;
}
- else
- {
- color.red = 33333;
- color.green = 33333;
- color.blue = 60000;
+ else {
+ if (position % 2 == 0)
+ {
+ color.red = color.green = color.blue = 0xf2 << 8;
+ }
+ else
+ {
+ color.red = 65535;
+ color.green = 65535;
+ color.blue = 65535;
+
+ }
}
- var state = this.get_state();
- this.event_box.modify_bg(state, color);
+ this.event_box.modify_bg(StateType.NORMAL, color);
+ this.arrow.modify_bg(StateType.NORMAL, color);
}
- public void
+ private void
update_id_card_label()
{
- string services_text = "";
+ // !!TODO: Use a table to format the labels and values
+ string service_spacer = "\n ";
- var display_name = Markup.printf_escaped("<big>%s</big>", this.id_card.display_name);
- for (int i = 0; i < id_card.services.length; i++)
+ var display_name = (manager_view.selection_in_progress() && this.id_card.is_no_identity()
+ ? _("Do not use a Moonshot identity for this service") : this.id_card.display_name);
+ var label_text = Markup.printf_escaped("<span rise='8000'><big>%s</big></span>", display_name);
+
+ if (is_selected)
{
- var service = id_card.services[i];
-
- if (i == (id_card.services.length - 1))
- services_text = services_text + Markup.printf_escaped("<i>%s</i>", service);
- else
- services_text = services_text + Markup.printf_escaped("<i>%s, </i>", service);
+ if (!this.id_card.is_no_identity()) {
+ label_text += "\n" + _("Username") + ": " + id_card.username;
+ label_text += "\n" + _("Realm:") + " " + id_card.issuer;
+ if (!id_card.trust_anchor.is_empty()) {
+ label_text += "\n" + _("Trust anchor: Enterprise provisioned");
+ }
+ }
+
+ string services_text = _("Services: ") + this.id_card.get_services_string(service_spacer);
+ label_text += "\n" + services_text;
}
- label.set_markup(display_name + "\n" + services_text);
+
+ label.set_markup(label_text);
}
- public IdCardWidget(IdCard id_card)
+ public IdCardWidget(IdCard id_card, IdentityManagerView manager_view)
{
this.id_card = id_card;
-
- var image = new Image.from_pixbuf(get_pixbuf(id_card));
+ this.manager_view = manager_view;
label = new Label(null);
label.set_alignment((float) 0, (float) 0.5);
update_id_card_label();
table = new Gtk.HBox(false, 6);
+ var image = new Image.from_pixbuf(get_pixbuf(id_card));
+ if (this.id_card.is_no_identity()) {
+ image.clear();
+ // Use padding to make the image size = 48x48 (size = 2x padding)
+ image.set_padding(24, 24);
+ }
table.pack_start(image, false, false, 0);
table.pack_start(label, true, true, 0);
-
- this.delete_button = new Button.with_label(_("Delete"));
- this.details_button = new Button.with_label(_("View details"));
- this.send_button = new Button.with_label(_("Send"));
- set_atk_name_description(delete_button, _("Delete"), _("Delete this ID Card"));
- set_atk_name_description(details_button, _("Details"), _("View the details of this ID Card"));
- set_atk_name_description(send_button, _("Send"), _("Send this ID Card"));
- this.hbutton_box = new HButtonBox();
- hbutton_box.pack_end(delete_button);
- hbutton_box.pack_end(details_button);
- hbutton_box.pack_end(send_button);
- send_button.set_sensitive(false);
-
- delete_button.clicked.connect(delete_button_cb);
- details_button.clicked.connect(details_button_cb);
- send_button.clicked.connect(send_button_cb);
+ this.arrow = new Arrow(ArrowType.RIGHT, ARROW_SHADOW);
+ table.pack_start(arrow, false, false);
this.main_vbox = new VBox(false, 12);
main_vbox.pack_start(table, true, true, 0);
- main_vbox.pack_start(hbutton_box, false, false, 0);
main_vbox.set_border_width(12);
event_box = new EventBox();
event_box.add(main_vbox);
event_box.button_press_event.connect(button_press_cb);
+ event_box.set_visible(false);
this.pack_start(event_box, true, true);
this.show_all();
- this.hbutton_box.hide();
set_idcard_color();
}
-
- private void set_atk_name_description(Widget widget, string name, string description)
- {
- var atk_widget = widget.get_accessible();
-
- atk_widget.set_name(name);
- atk_widget.set_description(description);
- }
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
}
public class IdentityManagerModel : Object {
+ static MoonshotLogger logger = get_logger("IdentityManagerModel");
+
private const string FILE_NAME = "identities.txt";
private PasswordHashTable password_table;
private IIdentityCardStore store;
identities.sort((a, b) => {
IdCard id_a = (IdCard )a;
IdCard id_b = (IdCard )b;
- if (id_a.IsNoIdentity() && !id_b.IsNoIdentity()) {
+ if (id_a.is_no_identity() && !id_b.is_no_identity()) {
return -1;
- } else if (id_b.IsNoIdentity() && !id_a.IsNoIdentity()) {
+ } else if (id_b.is_no_identity() && !id_a.is_no_identity()) {
return 1;
}
return strcmp(id_a.display_name, id_b.display_name);
});
- if (identities.is_empty || !identities[0].IsNoIdentity())
+ if (identities.is_empty || !identities[0].is_no_identity())
identities.insert(0, IdCard.NewNoIdentity());
foreach (IdCard id_card in identities) {
if (!id_card.store_password) {
return true;
}
- private bool remove_duplicates(IdCard card)
+ private bool remove_duplicates(IdCard new_card, out ArrayList<IdCard>? old_duplicates)
{
- bool duplicate_found = false;
- bool found = false;
- do {
- var cards = this.store.get_card_list();
- found = false;
- foreach (IdCard id_card in cards) {
- if ((card != id_card) && (id_card.nai == card.nai)) {
- stdout.printf("removing duplicate id for '%s'\n", card.nai);
- remove_card_internal(id_card);
- found = duplicate_found = true;
- break;
- }
+ ArrayList<IdCard> dups = new ArrayList<IdCard>();
+ var cards = this.store.get_card_list();
+ foreach (IdCard id_card in cards) {
+ if ((new_card != id_card) && (id_card.nai == new_card.nai)) {
+ dups.add(id_card);
+ }
+ }
+
+ foreach (IdCard id_card in dups) {
+ logger.trace("removing duplicate id for '%s'\n".printf(new_card.nai));
+ remove_card_internal(id_card);
+
+ if (new_card.trust_anchor.Compare(id_card.trust_anchor) == 0) {
+ logger.trace("Old and new cards have same trust anchor. Re-using the datetime_added and user_verified fields from the old card.");
+ new_card.trust_anchor.set_datetime_added(id_card.trust_anchor.datetime_added);
+ new_card.trust_anchor.user_verified = id_card.trust_anchor.user_verified;
}
- } while (found);
- return duplicate_found;
+ }
+
+ if (&old_duplicates != null) {
+ old_duplicates = dups;
+ }
+
+ return (dups.size > 0);
}
public IdCard? find_id_card(string nai, bool force_flat_file_store) {
return retval;
}
- public void add_card(IdCard card, bool force_flat_file_store) {
- if (card.temporary)
+ public void add_card(IdCard card, bool force_flat_file_store, out ArrayList<IdCard>? old_duplicates=null) {
+ if (card.temporary) {
+ logger.trace("add_card: card is temporary; returning.");
return;
+ }
string candidate;
IIdentityCardStore.StoreType saved_store_type = get_store_type();
if (force_flat_file_store)
set_store_type(IIdentityCardStore.StoreType.FLAT_FILE);
- remove_duplicates(card);
+ remove_duplicates(card, out old_duplicates);
if (!display_name_is_valid(card.display_name, out candidate))
{
if (!card.store_password)
password_table.CachePassword(card, store);
+
+ logger.trace("add_card: Adding card '%s' with services: '%s'"
+ .printf(card.display_name, card.get_services_string("; ")));
+
store.add_card(card);
set_store_type(saved_store_type);
card_list_changed();
}
public IdCard update_card(IdCard card) {
+ logger.trace("update_card");
+
IdCard retval;
if (card.temporary) {
retval = card;
public bool remove_card(IdCard card) {
if (remove_card_internal(card)) {
+ logger.trace(@"remove_card: Removed '$(card.display_name)'");
card_list_changed();
return true;
}
+ logger.warn(@"remove_card: Couldn't remove '$(card.display_name)'");
return false;
}
+ // The name is misleading: This not only sets the store type,
+ // it also creates a new store instance, which loads the card data.
public void set_store_type(IIdentityCardStore.StoreType type) {
if ((store != null) && (store.get_store_type() == type))
return;
store = new LocalFlatFileStore();
break;
}
+
+ // Loop through the loaded IDs. If any trust anchors are old enough that we didn't record
+ // the datetime_added, add it now.
+ string before_now = _("Before ") + TrustAnchor.format_datetime_now();
+ bool save_needed = false;
+ foreach (IdCard id in this.store.get_card_list()) {
+ if (!id.trust_anchor.is_empty() && id.trust_anchor.datetime_added == "") {
+ logger.trace("set_store_type : Set ta_datetime_added for old trust anchor on '%s' to '%s'".printf(id.display_name, before_now));
+ id.trust_anchor.set_datetime_added(before_now);
+ save_needed = true;
+ }
+ }
+ if (save_needed) {
+ this.store.store_id_cards();
+ }
}
public IIdentityCardStore.StoreType get_store_type() {
foreach (IdCard card in this.store.get_card_list()) {
// The 'NoIdentity' card is non-trivial if it has services or rules.
// All other cards are automatically non-trivial.
- if ((!card.IsNoIdentity()) ||
- (card.services.length > 0) ||
+ if ((!card.is_no_identity()) ||
+ (card.services.size > 0) ||
(card.rules.length > 0)) {
return true;
}
private IdentityManagerApp parent;
public IdentityManagerModel(IdentityManagerApp parent_app, IIdentityCardStore.StoreType store_type) {
+ logger.trace("IdentityManagerModel: store_type=" + store_type.to_string());
parent = parent_app;
password_table = new PasswordHashTable();
set_store_type(store_type);
--- /dev/null
+/*
+ * Copyright (c) 2016, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+*/
+
+using Gee;
+using Gtk;
+
+
+// Defined here as workaround for emacs vala-mode indentation failure.
+#if VALA_0_12
+static const string CANCEL = Stock.CANCEL;
+#else
+static const string CANCEL = STOCK_CANCEL;
+#endif
+
+
+// For use when exporting certificates.
+static string export_directory = null;
+
+class IdentityDialog : Dialog
+{
+ private static Gdk.Color white = make_color(65535, 65535, 65535);
+ private static Gdk.Color selected_color = make_color(0xd9 << 8, 0xf7 << 8, 65535);
+
+ private static MoonshotLogger logger = get_logger("IdentityDialog");
+
+ static const string displayname_labeltext = _("Display Name");
+ static const string realm_labeltext = _("Realm");
+ static const string username_labeltext = _("Username");
+ static const string password_labeltext = _("Password");
+
+ private Entry displayname_entry;
+ private Label displayname_label;
+ private Entry realm_entry;
+ private Label realm_label;
+ private Entry username_entry;
+ private Label username_label;
+ private Entry password_entry;
+ private Label password_label;
+ private CheckButton remember_checkbutton;
+ private Label message_label;
+ public bool complete;
+ private IdCard card;
+
+ private Label selected_item = null;
+
+ // Whether to clear the card's TrustAnchor after the user selects OK
+ internal bool clear_trust_anchor = false;
+
+ public string display_name {
+ get { return displayname_entry.get_text(); }
+ }
+
+ public string issuer {
+ get { return realm_entry.get_text(); }
+ }
+
+ public string username {
+ get { return username_entry.get_text(); }
+ }
+
+ public string password {
+ get { return password_entry.get_text(); }
+ }
+
+ public bool store_password {
+ get { return remember_checkbutton.active; }
+ }
+
+ internal ArrayList<string> get_services()
+ {
+ return card.services;
+ }
+
+ public IdentityDialog(IdentityManagerView parent)
+ {
+ this.with_idcard(null, _("Add ID Card"), parent);
+ }
+
+ public IdentityDialog.with_idcard(IdCard? a_card, string title, IdentityManagerView parent)
+ {
+ bool is_new_card = false;
+ if (a_card == null)
+ {
+ is_new_card = true;
+ }
+
+ card = a_card ?? new IdCard();
+ this.set_title(title);
+ this.set_modal(true);
+ this.set_transient_for(parent);
+
+ this.add_buttons(CANCEL, ResponseType.CANCEL, _("OK"), ResponseType.OK);
+ Box content_area = (Box) this.get_content_area();
+
+ displayname_label = new Label(@"$displayname_labeltext:");
+ displayname_label.set_alignment(0, (float) 0.5);
+ displayname_entry = new Entry();
+ displayname_entry.set_text(card.display_name);
+ displayname_entry.set_width_chars(40);
+
+ realm_label = new Label(@"$realm_labeltext:");
+ realm_label.set_alignment(0, (float) 0.5);
+ realm_entry = new Entry();
+ realm_entry.set_text(card.issuer);
+ realm_entry.set_width_chars(60);
+
+ username_label = new Label(@"$username_labeltext:");
+ username_label.set_alignment(0, (float) 0.5);
+ username_entry = new Entry();
+ username_entry.set_text(card.username);
+ username_entry.set_width_chars(40);
+
+ password_label = new Label(@"$password_labeltext:");
+ password_label.set_alignment(0, (float) 0.5);
+
+ remember_checkbutton = new CheckButton.with_label(_("Remember password"));
+ remember_checkbutton.active = card.store_password;
+
+ password_entry = new Entry();
+ password_entry.set_invisible_char('*');
+ password_entry.set_visibility(false);
+ password_entry.set_width_chars(40);
+ password_entry.set_text(card.password);
+
+ message_label = new Label("");
+ message_label.set_visible(false);
+
+ set_atk_relation(displayname_label, displayname_entry, Atk.RelationType.LABEL_FOR);
+ set_atk_relation(realm_label, realm_entry, Atk.RelationType.LABEL_FOR);
+ set_atk_relation(username_label, username_entry, Atk.RelationType.LABEL_FOR);
+ set_atk_relation(password_label, password_entry, Atk.RelationType.LABEL_FOR);
+
+ content_area.pack_start(message_label, false, false, 6);
+ add_as_vbox(content_area, displayname_label, displayname_entry);
+ add_as_vbox(content_area, username_label, username_entry);
+ add_as_vbox(content_area, realm_label, realm_entry);
+ add_as_vbox(content_area, password_label, password_entry);
+
+ var remember_hbox = new HBox(false, 40);
+ remember_hbox.pack_start(new HBox(false, 0), false, false, 0);
+ remember_hbox.pack_start(remember_checkbutton, false, false, 0);
+ content_area.pack_start(remember_hbox, false, false, 2);
+
+ this.response.connect(on_response);
+ content_area.set_border_width(6);
+
+ if (!is_new_card)
+ {
+ Widget trust_anchor_box = make_trust_anchor_box(card);
+ content_area.pack_start(trust_anchor_box, false, false, 15);
+
+ var services_vbox = make_services_vbox();
+ content_area.pack_start(services_vbox);
+ var services_vbox_bottom_spacer = new Alignment(0, 0, 0, 0);
+ services_vbox_bottom_spacer.set_size_request(0, 12);
+ content_area.pack_start(services_vbox_bottom_spacer, false, false, 0);
+ }
+
+ if (card.is_no_identity())
+ {
+ displayname_entry.set_sensitive(false);
+ realm_entry.set_sensitive(false);
+ username_entry.set_sensitive(false);
+ password_entry.set_sensitive(false);
+ remember_checkbutton.set_sensitive(false);
+ }
+
+ this.set_border_width(6);
+ this.set_resizable(false);
+ this.modify_bg(StateType.NORMAL, white);
+ this.show_all();
+ }
+
+ private Widget make_trust_anchor_box(IdCard id)
+ {
+
+ Label ta_label = new Label(_("Trust anchor: ")
+ + (id.trust_anchor.is_empty() ? _("None") : _("Enterprise provisioned")));
+ ta_label.set_alignment(0, 0.5f);
+
+ if (id.trust_anchor.is_empty()) {
+ return ta_label;
+ }
+
+
+ AttachOptions fill_and_expand = AttachOptions.EXPAND | AttachOptions.FILL;
+ AttachOptions fill = AttachOptions.FILL;
+
+ Table ta_table = new Table(6, 2, false);
+ int row = 0;
+
+ var ta_clear_button = new Button.with_label(_("Clear Trust Anchor"));
+ ta_clear_button.clicked.connect((w) => {
+ clear_trust_anchor = true;
+ ta_table.set_sensitive(false);
+ }
+ );
+
+ ta_table.attach(ta_label, 0, 1, row, row + 1, fill_and_expand, fill_and_expand, 0, 0);
+ ta_table.attach(ta_clear_button, 1, 2, row, row + 1, fill, fill, 0, 0);
+ row++;
+
+ Label added_label = new Label(_("Added : " + id.trust_anchor.datetime_added));
+ added_label.set_alignment(0, 0.5f);
+ ta_table.attach(added_label, 0, 1, row, row + 1, fill_and_expand, fill_and_expand, 20, 5);
+ row++;
+
+ if (id.trust_anchor.get_anchor_type() == TrustAnchor.TrustAnchorType.SERVER_CERT) {
+ Widget fingerprint = make_ta_fingerprint_widget(id.trust_anchor);
+ ta_table.attach(fingerprint, 0, 1, row, row + 2, fill_and_expand, fill_and_expand, 5, 5);
+
+ // To make the fingerprint box wider, try:
+ // ta_table.attach(fingerprint, 0, 2, row, row + 2, fill_and_expand, fill_and_expand, 20, 5);
+
+ }
+ else {
+ Label ca_cert_label = new Label(_("CA Certificate:"));
+ ca_cert_label.set_alignment(0, 0.5f);
+ var export_button = new Button.with_label(_("Export Certificate"));
+ //!!TODO!
+ export_button.clicked.connect((w) => {export_certificate(id);});
+
+ ta_table.attach(ca_cert_label, 0, 1, row, row + 1, fill_and_expand, fill_and_expand, 20, 0);
+ ta_table.attach(export_button, 1, 2, row, row + 1, fill, fill, 0, 0);
+ row++;
+
+ //!!TODO: When to show Subject, and when (if ever) show Subject-Altname here?
+ Label subject_label = new Label(_("Subject: ") + id.trust_anchor.subject);
+ subject_label.set_alignment(0, 0.5f);
+ ta_table.attach(subject_label, 0, 1, row, row + 1, fill_and_expand, fill_and_expand, 40, 5);
+ row++;
+
+ Label expiration_label = new Label(_("Expiration date: ") + id.trust_anchor.get_expiration_date());
+ expiration_label.set_alignment(0, 0.5f);
+ ta_table.attach(expiration_label, 0, 1, row, row + 1, fill_and_expand, fill_and_expand, 40, 5);
+ row++;
+
+ //!!TODO: What *is* this?
+ Label constraint_label = new Label(_("Constraint: "));
+ constraint_label.set_alignment(0, 0.5f);
+ ta_table.attach(constraint_label, 0, 1, row, row + 1, fill_and_expand, fill_and_expand, 20, 0);
+ row++;
+ }
+
+ return ta_table;
+
+ }
+
+ private static void add_as_vbox(Box content_area, Label label, Entry entry)
+ {
+ VBox vbox = new VBox(false, 2);
+
+ vbox.pack_start(label, false, false, 0);
+ vbox.pack_start(entry, false, false, 0);
+
+ // Hack to prevent the text entries from stretching horizontally
+ HBox hbox = new HBox(false, 0);
+ hbox.pack_start(vbox, false, false, 0);
+ content_area.pack_start(hbox, false, false, 6);
+ }
+
+ private static string update_preamble(string preamble)
+ {
+ if (preamble == "")
+ return _("Missing required field: ");
+ return _("Missing required fields: ");
+ }
+
+ private static string update_message(string old_message, string new_item)
+ {
+ string message;
+ if (old_message == "")
+ message = new_item;
+ else
+ message = old_message + ", " + new_item;
+ return message;
+ }
+
+ private static void check_field(string field, Label label, string fieldname, ref string preamble, ref string message)
+ {
+ if (field != "") {
+ label.set_markup(@"$fieldname:");
+ return;
+ }
+ label.set_markup(@"<span foreground=\"red\">$fieldname:</span>");
+ preamble = update_preamble(preamble);
+ message = update_message(message, fieldname);
+ }
+
+ private bool check_fields()
+ {
+ string preamble = "";
+ string message = "";
+ string password_test = store_password ? password : "not required";
+ if (!card.is_no_identity())
+ {
+ check_field(display_name, displayname_label, displayname_labeltext, ref preamble, ref message);
+ check_field(username, username_label, username_labeltext, ref preamble, ref message);
+ check_field(issuer, realm_label, realm_labeltext, ref preamble, ref message);
+ check_field(password_test, password_label, password_labeltext, ref preamble, ref message);
+ }
+ if (message != "") {
+ message_label.set_visible(true);
+ message_label.set_markup(@"<span foreground=\"red\">$preamble$message</span>");
+ return false;
+ }
+ return true;
+ }
+
+ private void on_response(Dialog source, int response_id)
+ {
+ switch (response_id) {
+ case ResponseType.OK:
+ complete = check_fields();
+ break;
+ case ResponseType.CANCEL:
+ complete = true;
+ break;
+ }
+ }
+
+ private VBox make_services_vbox()
+ {
+ logger.trace("make_services_vbox");
+
+ var services_vbox_alignment = new Alignment(0, 0, 1, 0);
+ var services_vscroll = new ScrolledWindow(null, null);
+ services_vscroll.set_policy(PolicyType.NEVER, PolicyType.AUTOMATIC);
+ services_vscroll.set_shadow_type(ShadowType.IN);
+ services_vscroll.set_size_request(0, 60);
+ services_vscroll.add_with_viewport(services_vbox_alignment);
+
+#if VALA_0_12
+ var remove_button = new Button.from_stock(Stock.REMOVE);
+#else
+ var remove_button = new Button.from_stock(STOCK_REMOVE);
+#endif
+ remove_button.set_sensitive(false);
+
+
+ var services_table = new Table(card.services.size, 1, false);
+ services_table.set_row_spacings(1);
+ services_table.set_col_spacings(0);
+ services_table.modify_bg(StateType.NORMAL, white);
+
+ var table_button_hbox = new HBox(false, 6);
+ table_button_hbox.pack_start(services_vscroll, true, true, 4);
+
+ // Hack to prevent the button from growing vertically
+ VBox fixed_height = new VBox(false, 0);
+ fixed_height.pack_start(remove_button, false, false, 0);
+ table_button_hbox.pack_start(fixed_height, false, false, 0);
+
+ // A table doesn't have a background color, so put it in an EventBox, and
+ // set the EventBox's background color instead.
+ EventBox table_bg = new EventBox();
+ table_bg.modify_bg(StateType.NORMAL, white);
+ table_bg.add(services_table);
+ services_vbox_alignment.add(table_bg);
+
+ var services_vbox_title = new Label(_("Services:"));
+ services_vbox_title.set_alignment(0, 0.5f);
+
+ var services_vbox = new VBox(false, 6);
+ services_vbox.pack_start(services_vbox_title, false, false, 0);
+ services_vbox.pack_start(table_button_hbox, true, true, 0);
+
+ int i = 0;
+ foreach (string service in card.services)
+ {
+ var label = new Label(service);
+ label.set_alignment((float) 0, (float) 0);
+ label.xpad = 3;
+
+ EventBox event_box = new EventBox();
+ event_box.modify_bg(StateType.NORMAL, white);
+ event_box.add(label);
+ event_box.button_press_event.connect(() =>
+ {
+ var state = label.get_state();
+ logger.trace("button_press_callback: Label state=" + state.to_string() + " setting bg to " + white.to_string());
+
+ if (selected_item == label)
+ {
+ // Deselect
+ selected_item.parent.modify_bg(state, white);
+ selected_item = null;
+ remove_button.set_sensitive(false);
+ }
+ else
+ {
+ if (selected_item != null)
+ {
+ // Deselect
+ selected_item.parent.modify_bg(state, white);
+ selected_item = null;
+ }
+
+ // Select
+ selected_item = label;
+ selected_item.parent.modify_bg(state, selected_color);
+ remove_button.set_sensitive(true);
+ }
+ return false;
+ });
+
+ services_table.attach_defaults(event_box, 0, 1, i, i+1);
+ i++;
+ }
+
+ remove_button.clicked.connect((remove_button) =>
+ {
+ var result = WarningDialog.confirm(this,
+ Markup.printf_escaped(
+ "<span font-weight='heavy'>You are about to remove the service '%s'.</span>",
+ selected_item.label)
+ + "\n\nAre you sure you want to do this?",
+ "delete_service");
+
+ if (result)
+ {
+ if (card != null) {
+ card.services.remove(selected_item.label);
+ services_table.remove(selected_item.parent);
+ selected_item = null;
+ remove_button.set_sensitive(false);
+ }
+ }
+
+ });
+
+ return services_vbox;
+ }
+
+ private void export_certificate(IdCard id)
+ {
+ var dialog = new FileChooserDialog("Save File",
+ this,
+ FileChooserAction.SAVE,
+ _("Cancel"),ResponseType.CANCEL,
+ _("Save"), ResponseType.ACCEPT,
+ null);
+ dialog.set_do_overwrite_confirmation(true);
+ if (export_directory != null) {
+ dialog.set_current_folder(export_directory);
+ }
+ // Remove slashes from the default filename.
+ string default_filename =
+ (id.display_name + ".pem").replace(Path.DIR_SEPARATOR_S, "_");
+ dialog.set_current_name(default_filename);
+ if (dialog.run() == ResponseType.ACCEPT)
+ {
+ // Export the certificate in PEM format.
+
+ const string CERT_HEADER = "-----BEGIN CERTIFICATE-----\n";
+ const string CERT_FOOTER = "\n-----END CERTIFICATE-----\n";
+
+ // Strip any embedded newlines in the certificate...
+ string cert = id.trust_anchor.ca_cert.replace("\n", "");
+
+ // Re-embed newlines every 64 chars.
+ string newcert = CERT_HEADER;
+ while (cert.length > 63) {
+ newcert += cert[0:64];
+ newcert += "\n";
+ cert = cert[64:cert.length];
+ }
+ if (cert.length > 0) {
+ newcert += cert;
+ }
+ newcert += CERT_FOOTER;
+
+ string filename = dialog.get_filename();
+ var file = File.new_for_path(filename);
+ var stream = file.replace(null, false, FileCreateFlags.PRIVATE);
+ stream.write(newcert.data);
+
+ // Save the parent directory to use as default for next save
+ export_directory = file.get_parent().get_path();
+ }
+ dialog.destroy();
+ }
+}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
*/
using Gee;
using Gtk;
+using WebProvisioning;
public class IdentityManagerView : Window {
static MoonshotLogger logger = get_logger("IdentityManagerView");
- private const int WINDOW_WIDTH = 400;
+ bool use_flat_file_store = false;
+
+ // The latest year in which Moonshot sources were modified.
+ private static int LATEST_EDIT_YEAR = 2016;
+
+ public static Gdk.Color white = make_color(65535, 65535, 65535);
+
+ private const int WINDOW_WIDTH = 700;
private const int WINDOW_HEIGHT = 500;
protected IdentityManagerApp parent_app;
#if OS_MACOS
#endif
private UIManager ui_manager = new UIManager();
private Entry search_entry;
- private VBox vbox_right;
- private VBox login_vbox;
- private VBox services_vbox;
private CustomVBox custom_vbox;
- private VBox services_internal_vbox;
- private ScrolledWindow services_vscroll;
- private Entry issuer_entry;
- private Entry username_entry;
- private Entry password_entry;
- private Label prompting_service;
- private Label no_identity_title;
- private CheckButton remember_checkbutton;
- private Button update_password_button;
+ private VBox service_prompt_vbox;
+ private Button edit_button;
+ private Button remove_button;
+ private Button send_button;
+
private Gtk.ListStore* listmodel;
private TreeModelFilter filter;
- public IdentityManagerModel identities_manager;
+ internal IdentityManagerModel identities_manager;
private unowned SList<IdCard> candidates;
- public GLib.Queue<IdentityRequest> request_queue;
+ private GLib.Queue<IdentityRequest> request_queue;
- private HashTable<Gtk.Button, string> service_button_map;
+ internal CheckButton remember_identity_binding = null;
+
+ private IdCard selected_idcard = null;
+
+ private string import_directory = null;
private enum Columns
{
N_COLUMNS
}
- private const string layout =
+ private const string menu_layout =
"<menubar name='MenuBar'>" +
- " <menu name='FileMenu' action='FileMenuAction'>" +
- " <menuitem name='AddIdCard' action='AddIdCardAction' />" +
- " <separator />" +
- " <menuitem name='Quit' action='QuitAction' />" +
- " </menu>" +
- "" +
" <menu name='HelpMenu' action='HelpMenuAction'>" +
" <menuitem name='About' action='AboutAction' />" +
" </menu>" +
"</menubar>";
- public IdentityManagerView(IdentityManagerApp app) {
+ public IdentityManagerView(IdentityManagerApp app, bool use_flat_file_store) {
parent_app = app;
+ this.use_flat_file_store = use_flat_file_store;
+
#if OS_MACOS
osxApp = OSXApplication.get_instance();
#endif
identities_manager = parent_app.model;
request_queue = new GLib.Queue<IdentityRequest>();
- service_button_map = new HashTable<Gtk.Button, string>(direct_hash, direct_equal);
- this.title = "Moonshot Identity Selector";
+ this.title = _("Moonshot Identity Selector");
this.set_position(WindowPosition.CENTER);
set_default_size(WINDOW_WIDTH, WINDOW_HEIGHT);
build_ui();
connect_signals();
}
- public void on_card_list_changed() {
+ private void on_card_list_changed() {
+ logger.trace("on_card_list_changed");
load_id_cards();
}
return true;
}
- if (id_card.services.length > 0)
+ if (id_card.services.size > 0)
{
foreach (string service in id_card.services)
{
filter.set_visible_func(visible_func);
}
- private void search_entry_icon_press_cb(EntryIconPosition pos, Gdk.Event event)
- {
- if (pos == EntryIconPosition.PRIMARY)
- {
- print("Search entry icon pressed\n");
- }
- else
- {
- this.search_entry.set_text("");
- }
- }
-
private void search_entry_text_changed_cb()
{
this.filter.refilter();
redraw_id_card_widgets();
-
- var has_text = this.search_entry.get_text_length() > 0;
- this.search_entry.set_icon_sensitive(EntryIconPosition.PRIMARY, has_text);
- this.search_entry.set_icon_sensitive(EntryIconPosition.SECONDARY, has_text);
-
- this.vbox_right.set_visible(false);
}
private bool search_entry_key_press_event_cb(Gdk.EventKey e)
return false;
}
- private void update_password_cb()
- {
- if (this.custom_vbox.current_idcard != null) {
- var identity = this.custom_vbox.current_idcard.id_card;
- var dialog = new AddPasswordDialog(identity, null);
- var result = dialog.run();
-
- switch (result) {
- case ResponseType.OK:
- identity.password = dialog.password;
- identity.store_password = dialog.remember;
- if (dialog.remember)
- identity.temporary = false;
- identity = identities_manager.update_card(identity);
- break;
- default:
- break;
- }
- dialog.destroy();
- }
- }
-
private void load_id_cards() {
- string current_idcard_nai = null;
- if (this.custom_vbox.current_idcard != null) {
- current_idcard_nai = custom_vbox.current_idcard.id_card.nai;
- custom_vbox.current_idcard = null;
- }
- var children = this.custom_vbox.get_children();
- foreach (var id_card_widget in children) {
- remove_id_card_widget((IdCardWidget)id_card_widget);
- }
+ logger.trace("load_id_cards");
+
+ custom_vbox.clear();
this.listmodel->clear();
LinkedList<IdCard> card_list = identities_manager.get_card_list() ;
if (card_list == null) {
}
foreach (IdCard id_card in card_list) {
+ logger.trace(@"load_id_cards: Loading card with display name '$(id_card.display_name)'");
add_id_card_data(id_card);
- IdCardWidget id_card_widget = add_id_card_widget(id_card);
- if (id_card_widget.id_card.nai == current_idcard_nai) {
- fill_details(id_card_widget);
- id_card_widget.expand();
- }
+ add_id_card_widget(id_card);
}
- if (custom_vbox.current_idcard == null)
- fill_details(null);
}
- private void fill_details(IdCardWidget? id_card_widget)
- {
- logger.trace("fill_details: id_card_widget=%s".printf(id_card_widget == null ? "null" : "non-null"));
-
- if (id_card_widget != null) {
- var id_card = id_card_widget.id_card;
- if (id_card.display_name == IdCard.NO_IDENTITY) {
- logger.trace("fill_details: Displaying title for NO_IDENTITY");
- login_vbox.hide();
- no_identity_title.show_all();
- } else {
- logger.trace("fill_details: Displaying details for selected card");
- this.issuer_entry.set_text(id_card.issuer);
- this.username_entry.set_text(id_card.username);
- this.password_entry.set_text(id_card.password ?? "");
- this.remember_checkbutton.active = id_card.store_password;
- no_identity_title.hide();
- login_vbox.show_all();
- }
-
- fill_services_vbox(id_card_widget.id_card);
- }
- }
-
- private void show_details(IdCard id_card)
- {
- this.vbox_right.set_visible(!vbox_right.get_visible());
-
- if (this.vbox_right.get_visible() == false)
- {
- this.resize(WINDOW_WIDTH, WINDOW_HEIGHT);
- }
- }
-
- private void details_identity_cb(IdCardWidget id_card_widget)
- {
- fill_details(id_card_widget);
- show_details(id_card_widget.id_card);
- }
-
- private IdCard get_id_card_data(AddIdentityDialog dialog)
+ private IdCard update_id_card_data(IdentityDialog dialog, IdCard id_card)
{
- var id_card = new IdCard();
-
id_card.display_name = dialog.display_name;
id_card.issuer = dialog.issuer;
id_card.username = dialog.username;
id_card.password = dialog.password;
id_card.store_password = dialog.store_password;
- id_card.services = {};
+
+ id_card.update_services_from_list(dialog.get_services());
+
+ if (dialog.clear_trust_anchor) {
+ id_card.clear_trust_anchor();
+ }
return id_card;
}
Columns.PASSWORD_COL, id_card.password);
}
- private void remove_id_card_data(IdCard id_card)
+ private IdCardWidget add_id_card_widget(IdCard id_card)
{
- TreeIter iter;
- string issuer;
+ logger.trace("add_id_card_widget: id_card.nai='%s'; selected nai='%s'"
+ .printf(id_card.nai,
+ this.selected_idcard == null ? "[null selection]" : this.selected_idcard.nai));
- if (listmodel->get_iter_first(out iter))
- {
- do
- {
- listmodel->get(iter,
- Columns.ISSUER_COL, out issuer);
- if (id_card.issuer == issuer)
- {
- listmodel->remove(iter);
- break;
- }
- }
- while (listmodel->iter_next(ref iter));
+ var id_card_widget = new IdCardWidget(id_card, this);
+ this.custom_vbox.add_id_card_widget(id_card_widget);
+ id_card_widget.expanded.connect(this.widget_selected_cb);
+ id_card_widget.collapsed.connect(this.widget_unselected_cb);
+
+ if (this.selected_idcard != null && this.selected_idcard.nai == id_card.nai) {
+ logger.trace(@"add_id_card_widget: Expanding selected idcard widget");
+ id_card_widget.expand();
}
+ return id_card_widget;
}
- private IdCardWidget add_id_card_widget(IdCard id_card)
+ private void widget_selected_cb(IdCardWidget id_card_widget)
{
- var id_card_widget = new IdCardWidget(id_card);
- this.custom_vbox.add_id_card_widget(id_card_widget);
- id_card_widget.details_id.connect(details_identity_cb);
- id_card_widget.remove_id.connect(remove_identity_cb);
- id_card_widget.send_id.connect((w) => send_identity_cb(w.id_card));
- id_card_widget.expanded.connect(this.custom_vbox.receive_expanded_event);
- id_card_widget.expanded.connect(fill_details);
- return id_card_widget;
+ logger.trace(@"widget_selected_cb: id_card_widget.id_card.display_name='$(id_card_widget.id_card.display_name)'");
+
+ this.selected_idcard = id_card_widget.id_card;
+ bool allow_removes = !id_card_widget.id_card.is_no_identity();
+ this.remove_button.set_sensitive(allow_removes);
+ this.edit_button.set_sensitive(true);
+ this.custom_vbox.receive_expanded_event(id_card_widget);
+
+ if (this.selection_in_progress())
+ this.send_button.set_sensitive(true);
+ }
+
+ private void widget_unselected_cb(IdCardWidget id_card_widget)
+ {
+ logger.trace(@"widget_unselected_cb: id_card_widget.id_card.display_name='$(id_card_widget.id_card.display_name)'");
+
+ this.selected_idcard = null;
+ this.remove_button.set_sensitive(false);
+ this.edit_button.set_sensitive(false);
+ this.custom_vbox.receive_collapsed_event(id_card_widget);
+
+ this.send_button.set_sensitive(false);
}
- public bool add_identity(IdCard id_card, bool force_flat_file_store)
+ public bool add_identity(IdCard id_card, bool force_flat_file_store, out ArrayList<IdCard>? old_duplicates=null)
{
#if OS_MACOS
/*
#else
Gtk.MessageDialog dialog;
IdCard? prev_id = identities_manager.find_id_card(id_card.nai, force_flat_file_store);
+ logger.trace("add_identity(flat=%s, card='%s'): find_id_card returned %s"
+ .printf(force_flat_file_store.to_string(), id_card.display_name, (prev_id != null ? prev_id.display_name : "null")));
if (prev_id!=null) {
int flags = prev_id.Compare(id_card);
+ logger.trace("add_identity: compare returned " + flags.to_string());
if (flags == 0) {
+ if (&old_duplicates != null) {
+ old_duplicates = new ArrayList<IdCard>();
+ }
+
return false; // no changes, no need to update
} else if ((flags & (1 << IdCard.DiffFlags.DISPLAY_NAME)) != 0) {
dialog = new Gtk.MessageDialog(this,
#endif
if (ret == Gtk.ResponseType.YES) {
- this.identities_manager.add_card(id_card, force_flat_file_store);
+ this.identities_manager.add_card(id_card, force_flat_file_store, out old_duplicates);
return true;
}
- return false;
+ else {
+ if (&old_duplicates != null) {
+ old_duplicates = new ArrayList<IdCard>();
+ }
+ return false;
+ }
}
- private void add_identity_manual_cb()
+ private void add_identity_cb()
{
- var dialog = new AddIdentityDialog();
+ var dialog = new IdentityDialog(this);
int result = ResponseType.CANCEL;
while (!dialog.complete)
result = dialog.run();
switch (result) {
case ResponseType.OK:
- this.identities_manager.add_card(get_id_card_data(dialog), false);
+ this.identities_manager.add_card(update_id_card_data(dialog, new IdCard()), false);
break;
default:
break;
dialog.destroy();
}
- private void remove_id_card_widget(IdCardWidget id_card_widget) {
- this.custom_vbox.remove_id_card_widget(id_card_widget);
+ private void edit_identity_cb(IdCard card)
+ {
+ var dialog = new IdentityDialog.with_idcard(card, _("Edit Identity"), this);
+ int result = ResponseType.CANCEL;
+ while (!dialog.complete)
+ result = dialog.run();
+
+ switch (result) {
+ case ResponseType.OK:
+ this.identities_manager.update_card(update_id_card_data(dialog, card));
+ break;
+ default:
+ break;
+ }
+ dialog.destroy();
}
- private void remove_identity(IdCardWidget id_card_widget)
+ private void remove_identity(IdCard id_card)
{
- var id_card = id_card_widget.id_card;
- remove_id_card_widget(id_card_widget);
+ logger.trace(@"remove_identity: id_card.display_name='$(id_card.display_name)'");
+ if (id_card != this.selected_idcard) {
+ logger.error("remove_identity: id_card != this.selected_idcard!");
+ }
+ this.selected_idcard = null;
this.identities_manager.remove_card(id_card);
+
+ // Nothing is selected, so disable buttons
+ this.edit_button.set_sensitive(false);
+ this.remove_button.set_sensitive(false);
+ this.send_button.set_sensitive(false);
}
private void redraw_id_card_widgets()
TreeIter iter;
IdCard id_card;
- var children = this.custom_vbox.get_children();
- foreach (var id_card_widget in children) {
- remove_id_card_widget((IdCardWidget )id_card_widget); //id_card_widget.destroy();
- }
+ this.custom_vbox.clear();
if (filter.get_iter_first(out iter))
{
}
}
- private void remove_identity_cb(IdCardWidget id_card_widget)
+ private void remove_identity_cb(IdCard id_card)
{
- var id_card = id_card_widget.id_card;
-
- var dialog = new MessageDialog(this,
- DialogFlags.DESTROY_WITH_PARENT,
- MessageType.QUESTION,
- Gtk.ButtonsType.YES_NO,
- _("Are you sure you want to delete %s ID Card?"), id_card.issuer);
- var result = dialog.run();
- switch (result) {
- case ResponseType.YES:
- remove_identity(id_card_widget);
- break;
- default:
- break;
- }
- dialog.destroy();
+ bool remove = WarningDialog.confirm(this,
+ Markup.printf_escaped(
+ "<span font-weight='heavy'>" + _("You are about to remove the identity '%s'.") + "</span>",
+ id_card.display_name)
+ + "\n\n" + _("Are you sure you want to do this?"),
+ "delete_idcard");
+ if (remove)
+ remove_identity(id_card);
+ }
+
+ private void set_prompting_service(string service)
+ {
+ clear_selection_prompts();
+
+ var prompting_service = new Label(_("Identity requested for service:\n%s").printf(service));
+ prompting_service.set_line_wrap(true);
+
+ // left-align
+ prompting_service.set_alignment(0, (float )0.5);
+
+ var selection_prompt = new Label(_("Select your identity:"));
+ selection_prompt.set_alignment(0, 1);
+
+ this.service_prompt_vbox.pack_start(prompting_service, false, false, 12);
+ this.service_prompt_vbox.pack_start(selection_prompt, false, false, 2);
+ this.service_prompt_vbox.show_all();
}
- public void set_prompting_service(string service)
+ private void clear_selection_prompts()
{
- prompting_service.set_label( _("Identity requested for service: %s").printf(service) );
+ var list = service_prompt_vbox.get_children();
+ foreach (Widget w in list)
+ {
+ service_prompt_vbox.remove(w);
+ }
}
+
public void queue_identity_request(IdentityRequest request)
{
- if (this.request_queue.is_empty())
+ bool queue_was_empty = !this.selection_in_progress();
+ this.request_queue.push_tail(request);
+
+ if (queue_was_empty)
{ /* setup widgets */
candidates = request.candidates;
filter.refilter();
redraw_id_card_widgets();
set_prompting_service(request.service);
+ remember_identity_binding.show();
+
+ if (this.selected_idcard != null
+ && this.custom_vbox.find_idcard_widget(this.selected_idcard) != null) {
+ // A widget is already selected, and has not been filtered out of the display via search
+ send_button.set_sensitive(true);
+ }
+
make_visible();
}
- this.request_queue.push_tail(request);
}
public IdCard check_add_password(IdCard identity, IdentityRequest request, IdentityManagerModel model)
{
+ logger.trace(@"check_add_password");
IdCard retval = identity;
bool idcard_has_pw = (identity.password != null) && (identity.password != "");
bool request_has_pw = (request.password != null) && (request.password != "");
- if ((!idcard_has_pw) && (!identity.IsNoIdentity())) {
+ if ((!idcard_has_pw) && (!identity.is_no_identity())) {
if (request_has_pw) {
identity.password = request.password;
retval = model.update_card(identity);
return retval;
}
- public void send_identity_cb(IdCard id)
+ private void send_identity_cb(IdCard id)
{
- IdCard identity = id;
- return_if_fail(request_queue.length > 0);
+ return_if_fail(this.selection_in_progress());
+
+ if (!check_and_confirm_trust_anchor(id)) {
+ // Allow user to pick again
+ return;
+ }
- candidates = null;
var request = this.request_queue.pop_head();
- identity = check_add_password(identity, request, identities_manager);
- if (this.request_queue.is_empty())
+ var identity = check_add_password(id, request, identities_manager);
+ send_button.set_sensitive(false);
+
+ candidates = null;
+
+ if (!this.selection_in_progress())
{
candidates = null;
- prompting_service.set_label(_(""));
+ clear_selection_prompts();
if (!parent_app.explicitly_launched) {
// The following occasionally causes the app to exit without sending the dbus
// reply, so for now we just don't exit
filter.refilter();
redraw_id_card_widgets();
- if ((identity != null) && (!identity.IsNoIdentity()))
+ if ((identity != null) && (!identity.is_no_identity()))
parent_app.default_id_card = identity;
- request.return_identity(identity);
- }
-
- private void label_make_bold(Label label)
- {
- var font_desc = new Pango.FontDescription();
-
- font_desc.set_weight(Pango.Weight.BOLD);
+ request.return_identity(identity, remember_identity_binding.active);
- /* This will only affect the weight of the font, the rest is
- * from the current state of the widget, which comes from the
- * theme or user prefs, since the font desc only has the
- * weight flag turned on.
- */
- label.modify_font(font_desc);
+ remember_identity_binding.active = false;
+ remember_identity_binding.hide();
}
- private void fill_services_vbox(IdCard id_card)
+ private bool check_and_confirm_trust_anchor(IdCard id)
{
- logger.trace("fill_services_vbox");
-
- var children = this.services_internal_vbox.get_children();
- foreach (var widget in children) {
- services_internal_vbox.remove(widget);
- }
-
- int i = 0;
- var n_rows = id_card.services.length;
-
- var services_table = new Table(n_rows, 2, false);
- services_table.set_col_spacings(10);
- services_table.set_row_spacings(10);
- this.services_internal_vbox.pack_start(services_table, true, false, 0);
-
- service_button_map.remove_all();
+ if (!id.trust_anchor.is_empty() && id.trust_anchor.get_anchor_type() == TrustAnchor.TrustAnchorType.SERVER_CERT) {
+ if (!id.trust_anchor.user_verified) {
- foreach (string service in id_card.services)
- {
- var label = new Label(service);
- label.set_alignment(0, (float) 0.5);
-#if VALA_0_12
- var remove_button = new Button.from_stock(Stock.REMOVE);
-#else
- var remove_button = new Button.from_stock(STOCK_REMOVE);
-#endif
+ bool ret = false;
+ int result = ResponseType.CANCEL;
+ var dialog = new TrustAnchorDialog(id, this);
+ while (!dialog.complete)
+ result = dialog.run();
+ switch (result) {
+ case ResponseType.OK:
+ id.trust_anchor.user_verified = true;
+ ret = true;
+ break;
+ default:
+ break;
+ }
- service_button_map.insert(remove_button, service);
-
- remove_button.clicked.connect((remove_button) =>
- {
- var candidate = service_button_map.lookup(remove_button);
- if (candidate == null)
- return;
- var dialog = new Gtk.MessageDialog(this,
- Gtk.DialogFlags.DESTROY_WITH_PARENT,
- Gtk.MessageType.QUESTION,
- Gtk.ButtonsType.YES_NO,
- _("Are you sure you want to stop '%s' ID Card from being used with %s?"),
- custom_vbox.current_idcard.id_card.display_name,
- candidate);
- var ret = dialog.run();
- dialog.hide();
-
- if (ret == Gtk.ResponseType.YES)
- {
- IdCard idcard = custom_vbox.current_idcard.id_card;
- if (idcard != null) {
- SList<string> services = new SList<string>();
-
- foreach (string srv in idcard.services)
- {
- if (srv == candidate)
- continue;
- services.append(srv);
- }
-
- idcard.services = new string[services.length()];
- for (int j = 0; j < idcard.services.length; j++)
- {
- idcard.services[j] = services.nth_data(j);
- }
-
- identities_manager.update_card(idcard);
- }
- }
-
- });
- services_table.attach_defaults(label, 0, 1, i, i+1);
- services_table.attach_defaults(remove_button, 1, 2, i, i+1);
- i++;
+ dialog.destroy();
+ return ret;
+ }
}
-
- services_vbox.show_all();
+ return true;
}
private void on_about_action()
{
- string[] authors = {
- "Javier Jardón <jjardon@codethink.co.uk>",
- "Sam Thursfield <samthursfield@codethink.co.uk>",
- "Alberto Ruiz <alberto.ruiz@codethink.co.uk>",
- null
- };
-
- string copyright = "Copyright 2011 JANET";
+ string copyright = "Copyright (c) 2011, %d JANET".printf(LATEST_EDIT_YEAR);
string license =
"""
-Copyright (c) 2011, JANET(UK)
+Copyright (c) 2011, %d JANET(UK)
All rights reserved.
Redistribution and use in source and binary forms, with or without
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
-""";
-
- Gtk.show_about_dialog(this,
- "comments", _("Moonshot project UI"),
- "copyright", copyright,
- "website", Config.PACKAGE_URL,
- "version", Config.PACKAGE_VERSION,
- "license", license,
- "website-label", _("Visit the Moonshot project web site"),
- "authors", authors,
- "translator-credits", _("translator-credits"),
- null
- );
+""".printf(LATEST_EDIT_YEAR);
+
+ AboutDialog about = new AboutDialog();
+
+ about.set_comments(_("Moonshot project UI"));
+ about.set_copyright(copyright);
+ about.set_website(Config.PACKAGE_URL);
+ about.set_website_label(_("Visit the Moonshot project web site"));
+
+ // Note: The package version is configured at the top of moonshot/ui/configure.ac
+ about.set_version(Config.PACKAGE_VERSION);
+ about.set_license(license);
+ about.set_modal(true);
+ about.set_transient_for(this);
+ about.response.connect((a, b) => {about.destroy();});
+ about.modify_bg(StateType.NORMAL, white);
+
+ about.run();
}
private Gtk.ActionEntry[] create_actions() {
Gtk.ActionEntry[] actions = new Gtk.ActionEntry[0];
- Gtk.ActionEntry filemenu = { "FileMenuAction",
- null,
- N_("_File"),
- null, null, null };
- actions += filemenu;
- Gtk.ActionEntry add = { "AddIdCardAction",
- #if VALA_0_12
- Stock.ADD,
- #else
- STOCK_ADD,
- #endif
- N_("Add ID Card"),
- null,
- N_("Add a new ID Card"),
- add_identity_manual_cb };
- actions += add;
- Gtk.ActionEntry quit = { "QuitAction",
- #if VALA_0_12
- Stock.QUIT,
- #else
- STOCK_QUIT,
- #endif
- N_("Quit"),
- "<control>Q",
- N_("Quit the application"),
- Gtk.main_quit };
- actions += quit;
-
Gtk.ActionEntry helpmenu = { "HelpMenuAction",
null,
N_("_Help"),
ui_manager.insert_action_group(action_group, 0);
try
{
- ui_manager.add_ui_from_string(layout, -1);
+ ui_manager.add_ui_from_string(menu_layout, -1);
}
catch (Error e)
{
private void build_ui()
{
+ // Note: On Debian7/Gtk+2, the menu bar remains gray. This doesn't happen on Debian8/Gtk+3.
+ this.modify_bg(StateType.NORMAL, white);
+
create_ui_manager();
+ int num_rows = 18;
+ int num_cols = 8;
+ int button_width = 1;
+
+ Table top_table = new Table(num_rows, 10, false);
+ top_table.set_border_width(12);
+
+ AttachOptions fill_and_expand = AttachOptions.EXPAND | AttachOptions.FILL;
+ AttachOptions fill = AttachOptions.FILL;
+ int row = 0;
+
+ service_prompt_vbox = new VBox(false, 0);
+ top_table.attach(service_prompt_vbox, 0, 1, row, row + 1, fill_and_expand, fill_and_expand, 12, 0);
+ row++;
+
+ string search_tooltip_text = _("Search for an identity or service");
this.search_entry = new Entry();
set_atk_name_description(search_entry, _("Search entry"), _("Search for a specific ID Card"));
- this.search_entry.set_icon_from_pixbuf(EntryIconPosition.PRIMARY,
- find_icon_sized("edit-find", Gtk.IconSize.MENU));
-// find_icon_sized("edit-find-symbolic", Gtk.IconSize.MENU));
- this.search_entry.set_icon_tooltip_text(EntryIconPosition.PRIMARY,
- _("Search identity or service"));
- this.search_entry.set_icon_sensitive(EntryIconPosition.PRIMARY, false);
-
this.search_entry.set_icon_from_pixbuf(EntryIconPosition.SECONDARY,
- find_icon_sized("process-stop", Gtk.IconSize.MENU));
-// find_icon_sized("edit-clear-symbolic", Gtk.IconSize.MENU));
+ find_icon_sized("edit-find", Gtk.IconSize.MENU));
this.search_entry.set_icon_tooltip_text(EntryIconPosition.SECONDARY,
- _("Clear the current search"));
- this.search_entry.set_icon_sensitive(EntryIconPosition.SECONDARY, false);
+ search_tooltip_text);
+
+ this.search_entry.set_tooltip_text(search_tooltip_text);
+ this.search_entry.set_icon_sensitive(EntryIconPosition.SECONDARY, false);
- this.search_entry.icon_press.connect(search_entry_icon_press_cb);
this.search_entry.notify["text"].connect(search_entry_text_changed_cb);
this.search_entry.key_press_event.connect(search_entry_key_press_event_cb);
+ this.search_entry.set_width_chars(24);
- this.custom_vbox = new CustomVBox(this, false, 6);
+ var search_label_markup ="<small>" + search_tooltip_text + "</small>";
+ var full_search_label = new Label(null);
+ full_search_label.set_markup(search_label_markup);
+ full_search_label.set_alignment(1, 0);
+
+ var search_vbox = new VBox(false, 0);
+ search_vbox.pack_start(search_entry, false, false, 0);
+ var search_spacer = new Alignment(0, 0, 0, 0);
+ search_spacer.set_size_request(0, 2);
+ search_vbox.pack_start(search_spacer, false, false, 0);
+ search_vbox.pack_start(full_search_label, false, false, 0);
+
+ // Overlap with the service_prompt_box
+ top_table.attach(search_vbox, 5, num_cols - button_width, row - 1, row + 1, fill_and_expand, fill, 0, 12);
+ row++;
+
+ this.custom_vbox = new CustomVBox(this, false, 2);
var viewport = new Viewport(null, null);
- viewport.set_border_width(6);
+ viewport.set_border_width(2);
viewport.set_shadow_type(ShadowType.NONE);
viewport.add(custom_vbox);
var id_scrollwin = new ScrolledWindow(null, null);
id_scrollwin.set_policy(PolicyType.NEVER, PolicyType.AUTOMATIC);
id_scrollwin.set_shadow_type(ShadowType.IN);
id_scrollwin.add_with_viewport(viewport);
- this.prompting_service = new Label(_(""));
- // left-align
- prompting_service.set_alignment(0, (float )0.5);
-
- var vbox_left = new VBox(false, 0);
- vbox_left.pack_start(search_entry, false, false, 6);
- vbox_left.pack_start(id_scrollwin, true, true, 0);
- vbox_left.pack_start(prompting_service, false, false, 6);
- vbox_left.set_size_request(WINDOW_WIDTH, 0);
-
- this.no_identity_title = new Label(_("No Identity: Send this identity to services which should not use Moonshot"));
- no_identity_title.set_alignment(0, (float ) 0.5);
- no_identity_title.set_line_wrap(true);
- no_identity_title.show();
-
- var login_vbox_title = new Label(_("Login: "));
- label_make_bold(login_vbox_title);
- login_vbox_title.set_alignment(0, (float) 0.5);
- var issuer_label = new Label(_("Issuer:"));
- issuer_label.set_alignment(1, (float) 0.5);
- this.issuer_entry = new Entry();
- issuer_entry.set_can_focus(false);
- var username_label = new Label(_("Username:"));
- username_label.set_alignment(1, (float) 0.5);
- this.username_entry = new Entry();
- username_entry.set_can_focus(false);
- var password_label = new Label(_("Password:"));
- password_label.set_alignment(1, (float) 0.5);
- this.password_entry = new Entry();
- password_entry.set_invisible_char('*');
- password_entry.set_visibility(false);
- password_entry.set_sensitive(false);
- this.remember_checkbutton = new CheckButton.with_label(_("Remember password"));
- remember_checkbutton.set_sensitive(false);
- this.update_password_button = new Button.with_label(_("Update Password"));
- this.update_password_button.clicked.connect(update_password_cb);
-
- set_atk_relation(issuer_label, issuer_entry, Atk.RelationType.LABEL_FOR);
- set_atk_relation(username_label, username_entry, Atk.RelationType.LABEL_FOR);
- set_atk_relation(password_entry, password_entry, Atk.RelationType.LABEL_FOR);
-
- // Create the login_vbox. This starts off hidden, because the first card we
- // display, by default, is NO_IDENTITY.
- var login_table = new Table(5, 2, false);
- login_table.set_col_spacings(10);
- login_table.set_row_spacings(10);
- login_table.attach_defaults(issuer_label, 0, 1, 0, 1);
- login_table.attach_defaults(issuer_entry, 1, 2, 0, 1);
- login_table.attach_defaults(username_label, 0, 1, 1, 2);
- login_table.attach_defaults(username_entry, 1, 2, 1, 2);
- login_table.attach_defaults(password_label, 0, 1, 2, 3);
- login_table.attach_defaults(password_entry, 1, 2, 2, 3);
- login_table.attach_defaults(remember_checkbutton, 1, 2, 3, 4);
- login_table.attach_defaults(update_password_button, 0, 1, 4, 5);
- var login_vbox_alignment = new Alignment(0, 0, 0, 0);
- login_vbox_alignment.set_padding(0, 0, 12, 0);
- login_vbox_alignment.add(login_table);
- this.login_vbox = new VBox(false, 6);
- login_vbox.pack_start(login_vbox_title, false, true, 0);
- login_vbox.pack_start(login_vbox_alignment, false, true, 0);
- login_vbox.hide();
-
- var services_vbox_title = new Label(_("Services:"));
- label_make_bold(services_vbox_title);
- services_vbox_title.set_alignment(0, (float) 0.5);
-
- this.services_internal_vbox = new VBox(true, 6);
-
- var services_vbox_alignment = new Alignment(0, 0, 0, 1);
- services_vbox_alignment.set_padding(6, 6, 6, 6);
- services_vbox_alignment.add(services_internal_vbox);
- services_vscroll = new ScrolledWindow(null, null);
- services_vscroll.set_policy(PolicyType.NEVER, PolicyType.AUTOMATIC);
- services_vscroll.set_shadow_type(ShadowType.IN);
- services_vscroll.add_with_viewport(services_vbox_alignment);
-
- services_vbox = new VBox(false, 6);
- this.vbox_right = new VBox(false, 18);
- services_vbox.pack_start(services_vbox_title, false, false, 0);
- services_vbox.pack_start(services_vscroll, true, true, 0);
-
- vbox_right.pack_start(no_identity_title, true, false, 0);
- vbox_right.pack_start(login_vbox, false, false, 0);
- vbox_right.pack_start(services_vbox, true, true, 0);
-
- var hbox = new HBox(false, 12);
- hbox.pack_start(vbox_left, false, false, 0);
- hbox.pack_start(vbox_right, true, true, 0);
+ top_table.attach(id_scrollwin, 0, num_cols - 1, row, num_rows - 1, fill_and_expand, fill_and_expand, 6, 0);
+
+ // Right below id_scrollwin:
+ remember_identity_binding = new CheckButton.with_label(_("Remember my identity choice for this service"));
+ remember_identity_binding.active = false;
+ top_table.attach(remember_identity_binding, 0, num_cols / 2, num_rows - 1, num_rows, fill_and_expand, fill_and_expand, 3, 0);
+
+ var add_button = new Button.with_label(_("Add"));
+ add_button.clicked.connect((w) => {add_identity_cb();});
+ top_table.attach(make_rigid(add_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
+ row++;
+
+ var import_button = new Button.with_label(_("Import"));
+ import_button.clicked.connect((w) => {import_identities_cb();});
+ top_table.attach(make_rigid(import_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
+ row++;
+
+ this.edit_button = new Button.with_label(_("Edit"));
+ edit_button.clicked.connect((w) => {edit_identity_cb(this.selected_idcard);});
+ edit_button.set_sensitive(false);
+ top_table.attach(make_rigid(edit_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
+ row++;
+
+ this.remove_button = new Button.with_label(_("Remove"));
+ remove_button.clicked.connect((w) => {remove_identity_cb(this.selected_idcard);});
+ remove_button.set_sensitive(false);
+ top_table.attach(make_rigid(remove_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
+ row++;
+
+ // push the send button down another row.
+ row++;
+ this.send_button = new Button.with_label(_("Send"));
+ send_button.clicked.connect((w) => {send_identity_cb(this.selected_idcard);});
+ // send_button.set_visible(false);
+ send_button.set_sensitive(false);
+ top_table.attach(make_rigid(send_button), num_cols - button_width, num_cols, row, row + 1, fill, fill, 0, 0);
+ row++;
var main_vbox = new VBox(false, 0);
- main_vbox.set_border_width(12);
- #if OS_MACOS
+#if OS_MACOS
// hide the File | Quit menu item which is now on the Mac Menu
- Gtk.Widget quit_item = this.ui_manager.get_widget("/MenuBar/FileMenu/Quit");
- quit_item.hide();
+// Gtk.Widget quit_item = this.ui_manager.get_widget("/MenuBar/FileMenu/Quit");
+// quit_item.hide();
Gtk.MenuShell menushell = this.ui_manager.get_widget("/MenuBar") as Gtk.MenuShell;
+ menushell.modify_bg(StateType.NORMAL, white);
+
osxApp.set_menu_bar(menushell);
osxApp.set_use_quartz_accelerators(true);
osxApp.sync_menu_bar();
- osxApp.ready();
+ osxApp.ready();
#else
var menubar = this.ui_manager.get_widget("/MenuBar");
main_vbox.pack_start(menubar, false, false, 0);
+ menubar.modify_bg(StateType.NORMAL, white);
#endif
- main_vbox.pack_start(hbox, true, true, 0);
+ main_vbox.pack_start(top_table, true, true, 6);
+
add(main_vbox);
main_vbox.show_all();
- this.vbox_right.hide();
+
+ if (!this.selection_in_progress())
+ remember_identity_binding.hide();
}
+ internal bool selection_in_progress() {
+ return !this.request_queue.is_empty();
+ }
+
private void set_atk_name_description(Widget widget, string name, string description)
{
var atk_widget = widget.get_accessible();
private void connect_signals()
{
- this.destroy.connect(Gtk.main_quit);
+ this.destroy.connect(() => {
+ logger.trace("Destroy event; calling Gtk.main_quit()");
+ Gtk.main_quit();
+ });
this.identities_manager.card_list_changed.connect(this.on_card_list_changed);
+ this.delete_event.connect(() => {return confirm_quit();});
+ }
+
+ private bool confirm_quit() {
+ logger.trace("delete_event intercepted; selection_in_progress()=" + selection_in_progress().to_string());
+
+ if (selection_in_progress()) {
+ var result = WarningDialog.confirm(this,
+ Markup.printf_escaped(
+ "<span font-weight='heavy'>" + _("Do you wish to use the %s service?") + "</span>",
+ this.request_queue.peek_head().service)
+ + "\n\n" + _("Select Yes to select an ID for this service, or No to cancel"),
+ "close_moonshot_window");
+ if (result) {
+ // Prevent other handlers from handling this event; this keeps the window open.
+ return true;
+ }
+ }
+
+ // Allow the window deletion to proceed.
+ return false;
}
- private static void set_atk_relation(Widget widget, Widget target_widget, Atk.RelationType relationship)
+ private static Widget make_rigid(Button button)
{
- var atk_widget = widget.get_accessible();
- var atk_target_widget = target_widget.get_accessible();
+ // Hack to prevent the button from growing vertically
+ VBox fixed_height = new VBox(false, 0);
+ fixed_height.pack_start(button, false, false, 0);
+
+ return fixed_height;
+ }
+
+ private void import_identities_cb() {
+ var dialog = new FileChooserDialog(_("Import File"),
+ this,
+ FileChooserAction.OPEN,
+ _("Cancel"),ResponseType.CANCEL,
+ _("Open"), ResponseType.ACCEPT,
+ null);
+
+ if (import_directory != null) {
+ dialog.set_current_folder(import_directory);
+ }
+
+ if (dialog.run() == ResponseType.ACCEPT)
+ {
+ // Save the parent directory to use as default for next save
+ string filename = dialog.get_filename();
+ var file = File.new_for_path(filename);
+ import_directory = file.get_parent().get_path();
+
+ int import_count = 0;
+
+ var webp = new Parser(filename);
+ dialog.destroy();
+ webp.parse();
+ logger.trace(@"import_identities_cb: Have $(webp.cards.length) IdCards");
+ foreach (IdCard card in webp.cards)
+ {
+
+ if (card == null) {
+ logger.trace(@"import_identities_cb: Skipping null IdCard");
+ continue;
+ }
- atk_widget.add_relationship(relationship, atk_target_widget);
+ if (!card.trust_anchor.is_empty()) {
+ string ta_datetime_added = TrustAnchor.format_datetime_now();
+ card.trust_anchor.set_datetime_added(ta_datetime_added);
+ logger.trace("import_identities_cb : Set ta_datetime_added for '%s' to '%s'; ca_cert='%s'; server_cert='%s'"
+ .printf(card.display_name, ta_datetime_added, card.trust_anchor.ca_cert, card.trust_anchor.server_cert));
+ }
+
+
+ bool result = add_identity(card, use_flat_file_store);
+ if (result) {
+ logger.trace(@"import_identities_cb: Added or updated '$(card.display_name)'");
+ import_count++;
+ }
+ else {
+ logger.trace(@"import_identities_cb: Did not add or update '$(card.display_name)'");
+ }
+ }
+ var msg_dialog = new Gtk.MessageDialog(this,
+ Gtk.DialogFlags.DESTROY_WITH_PARENT,
+ Gtk.MessageType.INFO,
+ Gtk.ButtonsType.OK,
+ _("Import completed. %d Identities were added or updated."),
+ import_count);
+ msg_dialog.run();
+ msg_dialog.destroy();
+ }
+ dialog.destroy();
}
+
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
}
#endif
- private const int WINDOW_WIDTH = 400;
- private const int WINDOW_HEIGHT = 500;
-
-
/** If we're successfully registered with DBus, then show the UI. Otherwise, wait until we're registered. */
public void show() {
if (name_is_owned) {
model.set_store_type(IIdentityCardStore.StoreType.KEYRING);
if (!headless)
- view = new IdentityManagerView(this);
+ view = new IdentityManagerView(this, use_flat_file_store);
LinkedList<IdCard> card_list = model.get_card_list();
if (card_list.size > 0)
this.default_id_card = card_list.last();
#endif
}
- public bool add_identity(IdCard id, bool force_flat_file_store) {
- if (view != null) return view.add_identity(id, force_flat_file_store);
- model.add_card(id, force_flat_file_store);
- return true;
+ public bool add_identity(IdCard id, bool force_flat_file_store, out ArrayList<IdCard>? old_duplicates=null) {
+ if (view != null)
+ {
+ logger.trace("add_identity: calling view.add_identity");
+ return view.add_identity(id, force_flat_file_store, out old_duplicates);
+ }
+ else {
+ logger.trace("add_identity: calling model.add_card");
+ model.add_card(id, force_flat_file_store, out old_duplicates);
+ return true;
+ }
}
public void select_identity(IdentityRequest request) {
- logger.trace("select_identity");
+ logger.trace("select_identity: request.nai=%s".printf(request.nai ?? "[null]"));
IdCard identity = null;
/* If NAI matches, use this id card */
if (has_nai && request.nai == id.nai)
{
+ logger.trace("select_identity: request has nai; returning " + id.display_name);
identity = id;
break;
}
/* If any service matches we add id card to the candidate list */
if (has_srv)
{
- foreach (string srv in id.services)
- {
- if (request.service == srv)
- {
- request.candidates.append(id);
- continue;
- }
+ if (id.services.contains(request.service)) {
+ logger.trace(@"select_identity: request has service '$(request.service); matched on '$(id.display_name)'");
+ request.candidates.append(id);
}
}
}
/* If more than one candidate we dissasociate service from all ids */
if ((identity == null) && has_srv && request.candidates.length() > 1)
{
+ logger.trace(@"select_identity: multiple candidates; removing service '$(request.service) from all.");
foreach (IdCard id in request.candidates)
{
- int i = 0;
- SList<string> services_list = null;
- bool has_service = false;
-
- foreach (string srv in id.services)
- {
- if (srv == request.service)
- {
- has_service = true;
- continue;
- }
- services_list.append(srv);
- }
-
- if (!has_service)
- continue;
-
- if (services_list.length() == 0)
- {
- id.services = {};
- continue;
- }
-
- string[] services = new string[services_list.length()];
- foreach (string srv in services_list)
- {
- services[i] = srv;
- i++;
- }
-
- id.services = services;
+ id.services.remove(request.service);
}
}
/* If there are no candidates we use the service matching rules */
if ((identity == null) && (request.candidates.length() == 0))
{
+ logger.trace("select_identity: No candidates; using service matching rules.");
foreach (IdCard id in model.get_card_list())
{
foreach (Rule rule in id.rules)
if (!match_service_pattern(request.service, rule.pattern))
continue;
+ logger.trace(@"select_identity: ID $(id.display_name) matched on service matching rules.");
request.candidates.append(id);
if (rule.always_confirm == "true")
}
if ((identity == null) && has_nai) {
+ logger.trace("select_identity: Creating temp identity");
// create a temp identity
string[] components = request.nai.split("@", 2);
identity = new IdCard();
if (!shown) {
GLib.error("Couldn't own name org.janet.Moonshot on dbus or show previously launched identity manager.");
} else {
- stdout.printf("Showed previously launched identity manager.\n");
+ stdout.printf(_("Showed previously launched identity manager.\n"));
GLib.Process.exit(0);
}
}
settings.set_long_property("gtk-menu-images", 0, "moonshot");
#endif
+ //TODO?? Do we need to call Intl.setlocale(LocaleCategory.MESSAGES, "");
Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
Intl.bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "UTF-8");
Intl.textdomain(Config.GETTEXT_PACKAGE);
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
public delegate void ReturnIdentityCallback(IdentityRequest request);
public class IdentityRequest : Object {
+ static MoonshotLogger logger = get_logger("IdentityRequest");
+
public IdCard? id_card = null;
public bool complete = false;
public bool select_default = false;
return false;
}
- public void return_identity(IdCard? id_card) {
+ public void return_identity(IdCard? id_card, bool update_card = true) {
this.id_card = id_card;
this.complete = true;
/* update id_card service list */
- if (id_card != null && this.service != null && this.service != "")
+ if (update_card && id_card != null && this.service != null && this.service != "")
{
- bool duplicate_service = false;
-
- foreach (string service in id_card.services)
- {
- if (service == this.service)
- duplicate_service = true;
- }
+ bool duplicate_service = id_card.services.contains(this.service);
+ logger.trace("return_identity: duplicate_service=" + duplicate_service.to_string());
if (duplicate_service == false)
{
- string[] services = new string[id_card.services.length + 1];
-
- for (int i = 0; i < id_card.services.length; i++)
- services[i] = id_card.services[i];
-
- services[id_card.services.length] = this.service;
- id_card.services = services;
+ logger.trace("return_identity: calling add_service");
+ id_card.services.add(this.service);
+ logger.trace("return_identity: back from add_service");
this.id_card = this.parent_app.model.update_card(id_card);
}
}
return_if_fail(callback != null);
+ logger.trace("return_identity: invoking callback");
callback(this);
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#if GNOME_KEYRING
public class KeyringStore : Object, IIdentityCardStore {
+ static MoonshotLogger logger = get_logger("KeyringStore");
+
private LinkedList<IdCard> id_card_list;
private const string keyring_store_attribute = "Moonshot";
private const string keyring_store_version = "1.0";
private const GnomeKeyring.ItemType item_type = GnomeKeyring.ItemType.GENERIC_SECRET;
public void add_card(IdCard card) {
+ logger.trace("add_card: Adding card '%s' with services: '%s'"
+ .printf(card.display_name, card.get_services_string("; ")));
+
id_card_list.add(card);
store_id_cards();
}
public IdCard? update_card(IdCard card) {
+ logger.trace("update_card");
+
id_card_list.remove(card);
id_card_list.add(card);
+
store_id_cards();
foreach (IdCard idcard in id_card_list) {
if (idcard.display_name == card.display_name) {
return idcard;
}
}
+
+ logger.error(@"update_card: card '$(card.display_name)' was not found after re-loading!");
return null;
}
int rules_patterns_index = -1;
int rules_always_confirm_index = -1;
string store_password = null;
+ string ca_cert = "";
+ string server_cert = "";
+ string subject = "";
+ string subject_alt = "";
+ bool user_verified = false;
+ string ta_datetime_added = "";
for (i = 0; i < entry.attributes.len; i++) {
var attribute = ((GnomeKeyring.Attribute *) entry.attributes.data)[i];
- string value = attribute.string_value;
+ string value = "";
+ if (attribute.type == GnomeKeyring.AttributeType.STRING) {
+ value = attribute.string_value;
+ }
+
if (attribute.name == "Issuer") {
id_card.issuer = value;
} else if (attribute.name == "Username") {
} else if (attribute.name == "DisplayName") {
id_card.display_name = value;
} else if (attribute.name == "Services") {
- id_card.services = value.split(";");
+ id_card.update_services(value.split(";"));
} else if (attribute.name == "Rules-Pattern") {
rules_patterns_index = i;
} else if (attribute.name == "Rules-AlwaysConfirm") {
rules_always_confirm_index = i;
} else if (attribute.name == "CA-Cert") {
- id_card.trust_anchor.ca_cert = value.strip();
+ ca_cert = value.strip();
} else if (attribute.name == "Server-Cert") {
- id_card.trust_anchor.server_cert = value;
+ server_cert = value;
} else if (attribute.name == "Subject") {
- id_card.trust_anchor.subject = value;
+ subject = value;
} else if (attribute.name == "Subject-Alt") {
- id_card.trust_anchor.subject_alt = value;
+ subject_alt = value;
} else if (attribute.name == "StorePassword") {
store_password = value;
+ } else if (attribute.name == "TA_User_Verified") {
+ user_verified = (value == "true");
+ } else if (attribute.name == "TA_DateTime_Added") {
+ ta_datetime_added = value;
}
}
+
+ var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, user_verified);
+ if (ta_datetime_added != "") {
+ ta.set_datetime_added(ta_datetime_added);
+ }
+ id_card.set_trust_anchor_from_store(ta);
+
if ((rules_always_confirm_index != -1) && (rules_patterns_index != -1)) {
string rules_patterns_all = ((GnomeKeyring.Attribute *) entry.attributes.data)[rules_patterns_index].string_value;
string rules_always_confirm_all = ((GnomeKeyring.Attribute *) entry.attributes.data)[rules_always_confirm_index].string_value;
}
}
- public void store_id_cards() {
+ internal void store_id_cards() {
+ logger.trace("store_id_cards");
clear_keyring();
foreach (IdCard id_card in this.id_card_list) {
/* workaround for Centos vala array property bug: use temp array */
var rules = id_card.rules;
- var services_array = id_card.services;
string[] rules_patterns = new string[rules.length];
string[] rules_always_conf = new string[rules.length];
}
string patterns = string.joinv(";", rules_patterns);
string always_conf = string.joinv(";", rules_always_conf);
- string services = string.joinv(";", services_array);
+ string services = id_card.get_services_string(";");
GnomeKeyring.AttributeList attributes = new GnomeKeyring.AttributeList();
uint32 item_id;
attributes.append_string(keyring_store_attribute, keyring_store_version);
attributes.append_string("Server-Cert", id_card.trust_anchor.server_cert);
attributes.append_string("Subject", id_card.trust_anchor.subject);
attributes.append_string("Subject-Alt", id_card.trust_anchor.subject_alt);
+ attributes.append_string("TA_User_Verified", id_card.trust_anchor.user_verified ? "true" : "false");
+ attributes.append_string("TA_DateTime_Added", id_card.trust_anchor.datetime_added);
attributes.append_string("StorePassword", id_card.store_password ? "yes" : "no");
GnomeKeyring.Result result = GnomeKeyring.item_create_sync(null,
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
using Gee;
public class LocalFlatFileStore : Object, IIdentityCardStore {
+ static MoonshotLogger logger = get_logger("LocalFlatFileStore");
+
private LinkedList<IdCard> id_card_list;
private const string FILE_NAME = "identities.txt";
id_card_list.remove(card);
id_card_list.add(card);
store_id_cards();
- foreach(IdCard idcard in id_card_list)
- if (idcard.display_name == card.display_name)
- return idcard;
+ foreach(IdCard idcard in id_card_list) {
+ if (idcard.display_name == card.display_name) {
+ return idcard;
+ }
+ }
+ logger.error(@"update_card: card '$(card.display_name)' was not found after re-loading!");
return null;
}
var key_file = new KeyFile();
var path = get_data_dir();
var filename = Path.build_filename(path, FILE_NAME);
+ logger.trace("load_id_cards: attempting to load from " + filename);
try {
key_file.load_from_file(filename, KeyFileFlags.NONE);
id_card.issuer = key_file.get_string(identity, "Issuer");
id_card.username = key_file.get_string(identity, "Username");
id_card.password = key_file.get_string(identity, "Password");
- id_card.services = key_file.get_string_list(identity, "Services");
+ id_card.update_services(key_file.get_string_list(identity, "Services"));
id_card.display_name = key_file.get_string(identity, "DisplayName");
if (key_file.has_key(identity, "StorePassword")) {
id_card.store_password = (key_file.get_string(identity, "StorePassword") == "yes");
}
// Trust anchor
- id_card.trust_anchor.ca_cert = key_file.get_string(identity, "CA-Cert").strip();
- id_card.trust_anchor.subject = key_file.get_string(identity, "Subject");
- id_card.trust_anchor.subject_alt = key_file.get_string(identity, "SubjectAlt");
- id_card.trust_anchor.server_cert = key_file.get_string(identity, "ServerCert");
-
+ string ca_cert = key_file.get_string(identity, "CA-Cert").strip();
+ string server_cert = key_file.get_string(identity, "ServerCert");
+ string subject = key_file.get_string(identity, "Subject");
+ string subject_alt = key_file.get_string(identity, "SubjectAlt");
+ bool user_verified = get_bool_setting(identity, "TA_User_Verified", false, key_file);
+ var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, user_verified);
+ string ta_datetime_added = get_string_setting(identity, "TA_DateTime_Added", "", key_file);
+ if (ta_datetime_added != "") {
+ ta.set_datetime_added(ta_datetime_added);
+ }
+ id_card.set_trust_anchor_from_store(ta);
id_card_list.add(id_card);
}
catch (Error e) {
+ logger.error("load_id_cards: Error while loading keyfile: %s\n".printf(e.message));
stdout.printf("Error: %s\n", e.message);
}
}
return path;
}
- public void store_id_cards() {
+ internal void store_id_cards() {
var key_file = new KeyFile();
foreach (IdCard id_card in this.id_card_list) {
+ logger.trace(@"store_id_cards: Storing '$(id_card.display_name)'");
+
/* workaround for Centos vala array property bug: use temp arrays */
var rules = id_card.rules;
- var services = id_card.services;
- string[] empty = {};
string[] rules_patterns = new string[rules.length];
string[] rules_always_conf = new string[rules.length];
key_file.set_string(id_card.display_name, "Password", id_card.password);
else
key_file.set_string(id_card.display_name, "Password", "");
- key_file.set_string_list(id_card.display_name, "Services", services ?? empty);
+
+ // Using id_card.services.to_array() seems to cause a crash, possibly due to
+ // an unowned reference to the array.
+ string[] svcs = new string[id_card.services.size];
+ for (int i = 0; i < id_card.services.size; i++) {
+ svcs[i] = id_card.services[i];
+ }
+
+ key_file.set_string_list(id_card.display_name, "Services", svcs);
if (rules.length > 0) {
key_file.set_string_list(id_card.display_name, "Rules-Patterns", rules_patterns);
key_file.set_string(id_card.display_name, "StorePassword", id_card.store_password ? "yes" : "no");
// Trust anchor
- key_file.set_string(id_card.display_name, "CA-Cert", id_card.trust_anchor.ca_cert ?? "");
- key_file.set_string(id_card.display_name, "Subject", id_card.trust_anchor.subject ?? "");
- key_file.set_string(id_card.display_name, "SubjectAlt", id_card.trust_anchor.subject_alt ?? "");
- key_file.set_string(id_card.display_name, "ServerCert", id_card.trust_anchor.server_cert ?? "");
+ key_file.set_string(id_card.display_name, "CA-Cert", id_card.trust_anchor.ca_cert);
+ key_file.set_string(id_card.display_name, "Subject", id_card.trust_anchor.subject);
+ key_file.set_string(id_card.display_name, "SubjectAlt", id_card.trust_anchor.subject_alt);
+ key_file.set_string(id_card.display_name, "ServerCert", id_card.trust_anchor.server_cert);
+ if (id_card.trust_anchor.datetime_added != "") {
+ key_file.set_string(id_card.display_name, "TA_DateTime_Added", id_card.trust_anchor.datetime_added);
+ }
+ key_file.set_boolean(id_card.display_name, "TA_User_Verified", id_card.trust_anchor.user_verified);
+ logger.trace(@"store_id_cards: Stored '$(id_card.display_name)'");
}
var text = key_file.to_data(null);
try {
var path = get_data_dir();
var filename = Path.build_filename(path, FILE_NAME);
+ logger.trace("store_id_cards: attempting to store to " + filename);
var file = File.new_for_path(filename);
var stream = file.replace(null, false, FileCreateFlags.PRIVATE);
#if GIO_VAPI_USES_ARRAYS
#endif
}
catch (Error e) {
+ logger.error("store_id_cards: Error while saving keyfile: %s\n".printf(e.message));
stdout.printf("Error: %s\n", e.message);
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#if USE_LOG4VALA
+static void glib_default_log_handler(string? log_domain, LogLevelFlags log_level, string message)
+{
+ Log4Vala.Logger logger = Log4Vala.Logger.get_logger(log_domain ?? "Glib");
+ stderr.printf(log_level.to_string() + " : " + message + "\n");
+ logger.error("Glib error level: " + log_level.to_string() + " : " + message);
+}
+
/** Logger class that wraps the Log4Vala logger */
public class MoonshotLogger : Object {
static bool logger_is_initialized = false;
public MoonshotLogger(string name) {
if (!logger_is_initialized) {
+ Log.set_default_handler(glib_default_log_handler);
+
//!! TODO: Don't hard-code the pathname.
Log4Vala.init("/home/dbreslau/log4vala.conf");
logger_is_initialized = true;
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
class AddPasswordDialog : Dialog
{
+ private static Gdk.Color white = make_color(65535, 65535, 65535);
+
private Entry password_entry;
private CheckButton remember_checkbutton;
public AddPasswordDialog(IdCard id_card, IdentityRequest? request)
{
- this.set_title(_("Please enter password for ") + id_card.display_name);
+ this.set_title(_("Moonshot - Password"));
this.set_modal(true);
+ this.modify_bg(StateType.NORMAL, white);
+
+ this.add_buttons(_("Cancel"), ResponseType.CANCEL,
+ _("Connect"), ResponseType.OK);
- if (request != null) {
- this.add_buttons(_("Send"), ResponseType.OK,
- _("Return to application"), ResponseType.CANCEL);
- } else {
- this.add_buttons(_("Done"), ResponseType.OK,
- _("Cancel"), ResponseType.CANCEL);
- }
this.set_default_response(ResponseType.OK);
var content_area = this.get_content_area();
((Box) content_area).set_spacing(12);
- Label service_label = null;
- Label service_value = null;
- if (request != null) {
- service_label = new Label(_("for use with:"));
- service_label.set_alignment(1, (float) 0.5);
- service_value = new Label(request.service);
- service_value.set_alignment(0, (float) 0.5);
- }
-
- var nai_label = new Label(_("Network Access Identifier:"));
- nai_label.set_alignment(1, (float) 0.5);
+ content_area.modify_bg(StateType.NORMAL, white);
+
+ Label dialog_label = new Label(_("Enter the password for " + id_card.display_name));
+ dialog_label.set_alignment(0, 0);
+
+ var nai_label = new Label(_("User (NAI):"));
+ nai_label.set_alignment(0, 1);
var nai_value = new Label(id_card.nai);
- nai_value.set_alignment(0, (float) 0.5);
+ nai_value.set_alignment(0, 0);
var password_label = new Label(_("Password:"));
- password_label.set_alignment(1, (float) 0.5);
+ password_label.set_alignment(0, (float) 1);
this.password_entry = new Entry();
password_entry.set_invisible_char('*');
password_entry.set_visibility(false);
password_entry.activates_default = true;
remember_checkbutton = new CheckButton.with_label(_("Remember password"));
- set_atk_relation(password_entry, password_entry, Atk.RelationType.LABEL_FOR);
+ set_atk_relation(password_label, password_entry, Atk.RelationType.LABEL_FOR);
- var table = new Table(4, 2, false);
+ var table = new Table(6, 1, false);
+ AttachOptions opts = AttachOptions.EXPAND | AttachOptions.FILL;
int row = 0;
- table.set_col_spacings(10);
- table.set_row_spacings(10);
- if (request != null) {
- table.attach_defaults(service_label, 0, 1, row, row + 1);
- table.attach_defaults(service_value, 1, 2, row, row + 1);
- row++;
- }
- table.attach_defaults(nai_label, 0, 1, row, row+1);
- table.attach_defaults(nai_value, 1, 2, row, row+1);
+ table.set_col_spacings(6);
+ table.set_row_spacings(0);
+ table.attach(dialog_label, 0, 1, row, row + 1, opts, opts, 0, 2);
+// table.attach_defaults(service_value, 1, 2, row, row + 1);
row++;
- table.attach_defaults(password_label, 0, 1, row, row+1);
- table.attach_defaults(password_entry, 1, 2, row, row+1);
+
+ VBox nai_vbox = new VBox(false, 0);
+ nai_vbox.pack_start(nai_label, false, false, 0);
+ nai_vbox.pack_start(nai_value, false, false, 0);
+ table.attach(nai_vbox, 0, 1, row, row + 1, opts, opts, 0, 12);
+ row++;
+
+ VBox password_vbox = new VBox(false, 1);
+ var empty_box2 = new VBox(false, 0);
+ empty_box2.set_size_request(0, 0);
+ password_vbox.pack_start(empty_box2, false, false, 3);
+ password_vbox.pack_start(password_label, false, false, 0);
+ password_vbox.pack_start(password_entry, false, false, 0);
+ table.attach(password_vbox, 0, 1, row, row + 1, opts, opts, 0, 0);
+ row++;
+
+ table.attach(remember_checkbutton, 0, 1, row, row + 1, opts, opts, 20, 2);
+ row++;
+
+ var empty_box3 = new VBox(false, 0);
+ empty_box3.set_size_request(0, 0);
+ table.attach(empty_box3, 0, 1, row, row + 1, opts, opts, 0, 10);
row++;
- table.attach_defaults(remember_checkbutton, 1, 2, row, row+1);
var vbox = new VBox(false, 0);
vbox.set_border_width(6);
//this.set_resizable(false);
this.show_all();
}
-
- private void set_atk_relation(Widget widget, Widget target_widget, Atk.RelationType relationship)
- {
- var atk_widget = widget.get_accessible();
- var atk_target_widget = target_widget.get_accessible();
-
- atk_widget.add_relationship(relationship, atk_target_widget);
- }
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
namespace WebProvisioning
-{
+{
bool check_stack(SList<string> stack, string[] reference) {
if (stack.length() < reference.length)
return false;
-
+
for (int i = 0; i < reference.length; i++)
{
if (stack.nth_data(i) != reference[i])
bool always_confirm_handler(SList<string> stack)
{
string[] always_confirm_path = {"always-confirm", "rule", "selection-rules", "identity", "identities"};
-
+
return check_stack(stack, always_confirm_path);
}
-
+
bool
pattern_handler(SList<string> stack)
{
string[] pattern_path = {"pattern", "rule", "selection-rules", "identity", "identities"};
-
+
return check_stack(stack, pattern_path);
}
bool server_cert_handler(SList<string> stack)
{
string[] server_cert_path = {"server-cert", "trust-anchor", "identity", "identities"};
-
+
return check_stack(stack, server_cert_path);
}
bool subject_alt_handler(SList<string> stack)
{
string[] subject_alt_path = {"subject-alt", "trust-anchor", "identity", "identities"};
-
+
return check_stack(stack, subject_alt_path);
}
bool subject_handler(SList<string> stack)
{
string[] subject_path = {"subject", "trust-anchor", "identity", "identities"};
-
+
return check_stack(stack, subject_path);
}
-
+
bool ca_cert_handler(SList<string> stack)
{
string[] ca_path = {"ca-cert", "trust-anchor", "identity", "identities"};
-
+
return check_stack(stack, ca_path);
}
bool realm_handler(SList<string> stack)
{
string[] realm_path = {"realm", "identity", "identities"};
-
+
return check_stack(stack, realm_path);
}
bool password_handler(SList<string> stack)
{
string[] password_path = {"password", "identity", "identities"};
-
+
return check_stack(stack, password_path);
}
bool user_handler(SList<string> stack)
{
string[] user_path = {"user", "identity", "identities"};
-
+
return check_stack(stack, user_path);
}
bool display_name_handler(SList<string> stack)
{
string[] display_name_path = {"display-name", "identity", "identities"};
-
+
return check_stack(stack, display_name_path);
}
-
+
public class Parser : Object
{
private static MoonshotLogger logger = new MoonshotLogger("WebProvisioning");
private void start_element_func(MarkupParseContext context,
string element_name,
string[] attribute_names,
- string[] attribute_values) throws MarkupError
+ string[] attribute_values) throws MarkupError
+ {
+ if (element_name == "identity")
{
- if (element_name == "identity")
- {
- logger.trace("start_element_func (%p): Adding an identity".printf(this));
- card = new IdCard();
- _cards += card;
- }
- else if (element_name == "rule")
- {
- card.add_rule(Rule());
- }
+ card = new IdCard();
+ _cards += card;
+
+ ta_ca_cert = "";
+ ta_server_cert = "";
+ ta_subject = "";
+ ta_subject_alt = "";
+ }
+ else if (element_name == "rule")
+ {
+ card.add_rule(Rule());
}
+ }
- private void
- text_element_func(MarkupParseContext context,
- string text,
- size_t text_len) throws MarkupError {
- unowned SList<string> stack = context.get_element_stack();
-
- if (text_len < 1)
- return;
-
- logger.trace("text_element_func (%p): text='%s'".printf(this, stack.nth_data(0)));
-
- if (stack.nth_data(0) == "display-name" && display_name_handler(stack))
- {
- card.display_name = text;
- }
- else if (stack.nth_data(0) == "user" && user_handler(stack))
- {
- card.username = text;
- }
- else if (stack.nth_data(0) == "password" && password_handler(stack))
- {
- card.password = text;
- }
- else if (stack.nth_data(0) == "realm" && realm_handler(stack))
- {
- card.issuer = text;
- }
- else if (stack.nth_data(0) == "service")
- {
- card.add_service(text);
+ private void end_element_func(MarkupParseContext context,
+ string element_name) throws MarkupError
+ {
+ if (element_name == "identity")
+ {
+ if (ta_ca_cert != "" || ta_server_cert != "") {
+ var ta = new TrustAnchor(ta_ca_cert,
+ ta_server_cert,
+ ta_subject,
+ ta_subject_alt,
+ false);
+ // Set the datetime_added in moonshot-server.vala, since it doesn't get sent via IPC
+ card.set_trust_anchor_from_store(ta);
}
+ }
+ }
+
+ private void
+ text_element_func(MarkupParseContext context,
+ string text,
+ size_t text_len) throws MarkupError {
+ unowned SList<string> stack = context.get_element_stack();
+
+ if (text_len < 1)
+ return;
+
+ if (stack.nth_data(0) == "display-name" && display_name_handler(stack))
+ {
+ card.display_name = text;
+ }
+ else if (stack.nth_data(0) == "user" && user_handler(stack))
+ {
+ card.username = text;
+ }
+ else if (stack.nth_data(0) == "password" && password_handler(stack))
+ {
+ card.password = text;
+ }
+ else if (stack.nth_data(0) == "realm" && realm_handler(stack))
+ {
+ card.issuer = text;
+ }
+ else if (stack.nth_data(0) == "service")
+ {
+ card.services.add(text);
+ }
- /* Rules */
- else if (stack.nth_data(0) == "pattern" && pattern_handler(stack))
- {
- /* use temp array to workaround valac 0.10 bug accessing array property length */
+ /* Rules */
+ else if (stack.nth_data(0) == "pattern" && pattern_handler(stack))
+ {
+ /* use temp array to workaround valac 0.10 bug accessing array property length */
+ var temp = card.rules;
+ card.rules[temp.length - 1].pattern = text;
+ }
+ else if (stack.nth_data(0) == "always-confirm" && always_confirm_handler(stack))
+ {
+ if (text == "true" || text == "false") {
+ /* use temp array to workaround valac 0.10 bug accessing array property length*/
var temp = card.rules;
- card.rules[temp.length - 1].pattern = text;
- }
- else if (stack.nth_data(0) == "always-confirm" && always_confirm_handler(stack))
- {
- if (text == "true" || text == "false") {
- /* use temp array to workaround valac 0.10 bug accessing array property length*/
- var temp = card.rules;
- card.rules[temp.length - 1].always_confirm = text;
- }
- }
- /*Trust anchor*/
- else if (stack.nth_data(0) == "ca-cert" && ca_cert_handler(stack))
- {
- card.trust_anchor.ca_cert = text;
- }
- else if (stack.nth_data(0) == "subject" && subject_handler(stack))
- {
- card.trust_anchor.subject = text;
- }
- else if (stack.nth_data(0) == "subject-alt" && subject_alt_handler(stack))
- {
- card.trust_anchor.subject_alt = text;
- }
- else if (stack.nth_data(0) == "server-cert" && server_cert_handler(stack))
- {
- card.trust_anchor.server_cert = text;
+ card.rules[temp.length - 1].always_confirm = text;
}
}
-
-
+ else if (stack.nth_data(0) == "ca-cert" && ca_cert_handler(stack))
+ {
+ ta_ca_cert = text ?? "";
+ }
+ else if (stack.nth_data(0) == "server-cert" && server_cert_handler(stack))
+ {
+ ta_server_cert = text ?? "";
+ }
+ else if (stack.nth_data(0) == "subject" && subject_handler(stack))
+ {
+ ta_subject = text;
+ }
+ else if (stack.nth_data(0) == "subject-alt" && subject_alt_handler(stack))
+ {
+ ta_subject_alt = text;
+ }
+ }
private const MarkupParser parser = {
- start_element_func, null, text_element_func, null, null
+ start_element_func, end_element_func, text_element_func, null, null
};
private MarkupParseContext ctx;
private string text;
private string path;
+ private string ta_ca_cert;
+ private string ta_server_cert;
+ private string ta_subject;
+ private string ta_subject_alt;
+
private IdCard card;
private IdCard[] _cards = {};
this.path = path;
var file = File.new_for_path(path);
-
+
try
{
var dis = new DataInputStream(file.read());
string line;
- while ((line = dis.read_line(null)) != null)
+ while ((line = dis.read_line(null)) != null) {
text += line;
+
+ // Preserve newlines.
+ //
+ // This may add an extra newline at EOF. Maybe use
+ // dis.read_upto("\n", ...) followed by dis.read_byte() instead?
+ text += "\n";
+ }
}
catch(GLib.Error e)
{
error("Could not retreive file size");
}
-
- logger.trace(@"Parser(): read text to parse; length=$(text.length)");
}
public void parse() {
catch(GLib.Error e)
{
error("Could not parse %s, invalid content", path);
- }
+ }
}
}
}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
+using Gee;
+
#if IPC_DBUS
[DBus (name = "org.janet.Moonshot")]
var id_card = request.id_card;
- if ((id_card != null) && (id_card.display_name != IdCard.NO_IDENTITY)) {
+ if ((id_card != null) && (!id_card.is_no_identity())) {
nai_out = id_card.nai;
if ((request.password != null) && (request.password != ""))
password_out = request.password;
if (subject_alt_name_constraint == null)
subject_alt_name_constraint = "";
- logger.trace("MoonshotServer.get_identity: returning true");
+ logger.trace(@"MoonshotServer.get_identity: returning with nai_out=$nai_out");
return true;
}
if ((password != null) && (password != ""))
idcard.store_password = true;
idcard.issuer = realm;
- idcard.services = services;
- idcard.trust_anchor.ca_cert = ca_cert;
- idcard.trust_anchor.subject = subject;
- idcard.trust_anchor.subject_alt = subject_alt;
- idcard.trust_anchor.server_cert = server_cert;
+ idcard.update_services(services);
+ var ta = new TrustAnchor(ca_cert, server_cert, subject, subject_alt, false);
+
+ if (!ta.is_empty()) {
+ // We have to set the datetime_added here, because it isn't delivered via IPC.
+ string ta_datetime_added = TrustAnchor.format_datetime_now();
+ ta.set_datetime_added(ta_datetime_added);
+ logger.trace("install_id_card : Set ta_datetime_added for '%s' to '%s'; ca_cert='%s'; server_cert='%s'".printf(idcard.display_name, ta.datetime_added, ta.ca_cert, ta.server_cert));
+ }
+ idcard.set_trust_anchor_from_store(ta);
+
+ logger.trace("install_id_card: Card '%s' has services: '%s'"
+ .printf(idcard.display_name, idcard.get_services_string("; ")));
+
+ logger.trace(@"Installing IdCard named '$(idcard.display_name)'; ca_cert='$(idcard.trust_anchor.ca_cert)'; server_cert='$(idcard.trust_anchor.server_cert)'");
+
if (rules_patterns.length == rules_always_confirm.length)
{
idcard.rules = rules;
}
- return parent_app.add_identity(idcard, force_flat_file_store!=0);
+ ArrayList<IdCard>? old_duplicates = null;
+ var ret = parent_app.add_identity(idcard, (force_flat_file_store != 0), out old_duplicates);
+
+ if (old_duplicates != null) {
+ // Printing to stdout here is ugly behavior; but it's old behavior that
+ // may be expected. (TODO: Do we need to keep this?)
+ foreach (IdCard id_card in old_duplicates) {
+ stdout.printf("removed duplicate id for '%s'\n", id_card.nai);
+ }
+ }
+ return ret;
}
}
}
+
+ // prevent a crash by holding the reference to otherwise
+ // unowned array(?)
+
+ // string[] svcs = card.services.to_array();
+ // string[] svcs = card.services.to_array()[:];
+ string[] svcs = new string[card.services.size];
+ for (int i = 0; i < card.services.size; i++) {
+ svcs[i] = card.services[i];
+ }
+
+ logger.trace(@"install_from_file: Adding card with display name '$(card.display_name)'");
result = install_id_card(card.display_name,
card.username,
card.password,
card.issuer,
rules_patterns,
rules_always_confirm,
- card.services,
+ svcs,
card.trust_anchor.ca_cert,
card.trust_anchor.subject,
card.trust_anchor.subject_alt,
mutex.lock();
+ ArrayList<IdCard>? old_duplicates = null;
// Defer addition to the main loop thread.
Idle.add(() => {
mutex.lock();
- success = parent_app.add_identity(idcard, force_flat_file_store);
+ success = parent_app.add_identity(idcard, force_flat_file_store, out old_duplicates);
+ foreach (IdCard id_card in old_duplicates) {
+ stdout.printf("removing duplicate id for '%s'\n", new_card.nai);
+ }
cond.signal();
mutex.unlock();
return false;
--- /dev/null
+/*
+ * Copyright (c) 2011-2016, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+*/
+
+using Gtk;
+
+
+private MoonshotLogger logger()
+{
+ return get_logger("MoonshotSettings");
+}
+
+static const string KEY_FILE_NAME="moonshot-ui.config";
+
+private KeyFile get_keyfile()
+{
+ KeyFile key_file = new KeyFile();
+ string config_dir = Environment.get_user_config_dir();
+ logger().trace("get_keyfile: config_dir=" + config_dir);
+
+ File dir = File.new_for_path(config_dir);
+ string path = dir.get_child(KEY_FILE_NAME).get_path();
+
+ try {
+ if (key_file.load_from_file(path, KeyFileFlags.NONE))
+ logger().trace("get_keyfile: load_from_file returned successfully");
+ else
+ logger().trace("get_keyfile: load_from_file returned false");
+ }
+ catch (FileError e) {
+ logger().trace("get_keyfile: FileError: " + e.message);
+ }
+ catch (KeyFileError e) {
+ logger().trace("get_keyfile: KeyFileError: " + e.message);
+ }
+
+ return key_file;
+}
+
+
+private void save_keyfile(KeyFile key_file)
+{
+ string config_dir = Environment.get_user_config_dir();
+ File dest = null;
+
+ // Make the directory if it doesn't already exist; ignore errors.
+ try {
+ File dir = File.new_for_path(config_dir);
+ dest = dir.get_child(KEY_FILE_NAME);
+ dir.make_directory_with_parents();
+ } catch (Error e) {
+ logger().trace("save_keyfile: make_directory_with_parents threw error (this is usually ignorable) : " + e.message);
+ }
+
+ // It would be nice to use key_file.save_to_file, but the binding doesn't exist
+ // in earlier versions of valac
+ // key_file.save_to_file(path.get_path());
+
+ string data = key_file.to_data();
+ try {
+ logger().trace("save_keyfile: saving to file path '%s'".printf(dest.get_path()));
+ // FileOutputStream s = dest.create(FileCreateFlags.REPLACE_DESTINATION | FileCreateFlags.PRIVATE);
+ // var ds = new DataOutputStream(s);
+ // ds.put_string(data);
+ string new_etag;
+ dest.replace_contents(data.data, null, false, FileCreateFlags.REPLACE_DESTINATION | FileCreateFlags.PRIVATE, out new_etag);
+ }
+ catch(Error e) {
+ logger().error("save_keyfile: error when writing to file: " + e.message);
+ }
+
+ // streams close automatically
+}
+
+internal void set_bool_setting(string group_name, string key_name, bool value, KeyFile? key_file=null)
+{
+ KeyFile tmp_key_file = null;
+ if (key_file == null) {
+ // Use tmp_key_file to hold an owned reference (since key_file is unowned)
+ tmp_key_file = get_keyfile();
+ key_file = tmp_key_file;
+ }
+
+ key_file.set_boolean(group_name, key_name, value);
+
+ if (tmp_key_file != null) {
+ // This is a "one-shot" settings update; save it now.
+ save_keyfile(key_file);
+ }
+}
+
+internal bool get_bool_setting(string group_name, string key_name, bool default=false, KeyFile? key_file=null)
+{
+ KeyFile tmp_key_file = null;
+ if (key_file == null) {
+ // Use tmp_key_file to hold an owned reference (since key_file is unowned)
+ tmp_key_file = get_keyfile();
+ key_file = tmp_key_file;
+ }
+
+ if (key_file == null)
+ return default;
+
+ try {
+ if (!key_file.has_key(group_name, key_name))
+ {
+ logger().info(@"get_bool_setting : key file doesn't contain key '$key_name' in group '$group_name'");
+ return default;
+ }
+ }
+ catch(KeyFileError e) {
+ logger().info(@"get_bool_setting : KeyFileError checking if key '$key_name' exists in group '$group_name' (maybe ignorable?) : " + e.message);
+ }
+
+ try {
+ // throws KeyFileError if key is not found
+ return key_file.get_boolean(group_name, key_name);
+ }
+ catch (KeyFileError e) {
+ logger().info("get_bool_setting got KeyFileError (may be ignorable) : " + e.message);
+ }
+ return default;
+}
+
+
+internal void set_string_setting(string group_name, string key_name, string value, KeyFile? key_file=null)
+{
+ KeyFile tmp_key_file = null;
+ if (key_file == null) {
+ // Use tmp_key_file to hold an owned reference (since key_file is unowned)
+ tmp_key_file = get_keyfile();
+ key_file = tmp_key_file;
+ }
+
+ key_file.set_string(group_name, key_name, value);
+ if (tmp_key_file != null) {
+ // This is a "one-shot" settings update; save it now.
+ save_keyfile(key_file);
+ }
+}
+
+internal string get_string_setting(string group_name, string key_name, string default="", KeyFile? key_file=null)
+{
+ KeyFile tmp_key_file = null;
+ if (key_file == null) {
+ // Use tmp_key_file to hold an owned reference (since key_file is unowned)
+ tmp_key_file = get_keyfile();
+ key_file = tmp_key_file;
+ }
+
+ if (key_file == null)
+ return default;
+
+ try {
+ if (!key_file.has_key(group_name, key_name))
+ {
+ logger().info(@"get_string_setting : key file doesn't contain key '$key_name' in group '$group_name'");
+ return default;
+ }
+ }
+ catch(KeyFileError e) {
+ logger().info(@"get_string_setting : KeyFileError checking if key '$key_name' exists in group '$group_name' (maybe ignorable?) : " + e.message);
+ }
+
+ try {
+ // throws KeyFileError if key is not found
+ return key_file.get_string(group_name, key_name);
+ }
+ catch (KeyFileError e) {
+ logger().info("get_string_setting got KeyFileError (may be ignorable) : " + e.message);
+ }
+ return default;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011-2016, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+*/
+using Gtk;
+
+class TrustAnchorDialog : Dialog
+{
+ private static Gdk.Color white = make_color(65535, 65535, 65535);
+
+ public bool complete = false;
+
+ public TrustAnchorDialog(IdCard idcard, Window parent)
+ {
+ this.set_title(_("Trust Anchor"));
+ this.set_modal(true);
+ this.set_transient_for(parent);
+ this.modify_bg(StateType.NORMAL, white);
+
+ this.add_buttons(_("Cancel"), ResponseType.CANCEL,
+ _("Confirm"), ResponseType.OK);
+
+ this.set_default_response(ResponseType.OK);
+
+ var content_area = this.get_content_area();
+ ((Box) content_area).set_spacing(12);
+ content_area.modify_bg(StateType.NORMAL, white);
+
+ Label dialog_label = new Label("");
+ dialog_label.set_alignment(0, 0);
+
+ string label_markup = "<span font-weight='heavy'>" + _("You are using this identity for the first time with the following trust anchor:") + "</span>";
+
+ dialog_label.set_markup(label_markup);
+ dialog_label.set_line_wrap(true);
+ dialog_label.set_width_chars(60);
+
+ var user_label = new Label(_("Username: ") + idcard.username);
+ user_label.set_alignment(0, 0.5f);
+
+ var realm_label = new Label(_("Realm: ") + idcard.issuer);
+ realm_label.set_alignment(0, 0.5f);
+
+ Label confirm_label = new Label(_("Please confirm that this is the correct trust anchor."));
+ confirm_label.set_alignment(0, 0.5f);
+
+ var trust_anchor_display = make_ta_fingerprint_widget(idcard.trust_anchor);
+
+ var vbox = new VBox(false, 0);
+ vbox.set_border_width(6);
+ vbox.pack_start(dialog_label, true, true, 12);
+ vbox.pack_start(user_label, true, true, 2);
+ vbox.pack_start(realm_label, true, true, 2);
+ vbox.pack_start(trust_anchor_display, true, true, 0);
+ vbox.pack_start(confirm_label, true, true, 12);
+
+ ((Container) content_area).add(vbox);
+
+ this.set_border_width(6);
+ this.set_resizable(false);
+
+ this.response.connect(on_response);
+
+ this.show_all();
+ }
+
+ private void on_response(Dialog source, int response_id)
+ {
+ switch (response_id) {
+ case ResponseType.OK:
+ complete = true;
+ break;
+ case ResponseType.CANCEL:
+ complete = true;
+ break;
+ }
+ }
+}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
+using Gtk;
+using Pango;
+
#if OS_WIN32
extern string? g_win32_get_package_installation_directory_of_module(void *module);
#endif
}
return false;
}
+
+internal Gdk.Color make_color(uint16 red, uint16 green, uint16 blue)
+{
+ Gdk.Color color = Gdk.Color();
+ color.red = red;
+ color.green = green;
+ color.blue = blue;
+
+ return color;
+}
+
+internal void set_atk_relation(Widget widget, Widget target_widget, Atk.RelationType relationship)
+{
+ var atk_widget = widget.get_accessible();
+ var atk_target_widget = target_widget.get_accessible();
+
+ atk_widget.add_relationship(relationship, atk_target_widget);
+}
+
+
+internal Widget make_ta_fingerprint_widget(TrustAnchor trust_anchor)
+{
+ var fingerprint_label = new Label(_("SHA-256 fingerprint:"));
+ fingerprint_label.set_alignment(0, 0.5f);
+
+ var fingerprint = new TextView();
+ var fontdesc = FontDescription.from_string("monospace 10");
+ fingerprint.modify_font(fontdesc);
+ fingerprint.set_editable(false);
+ fingerprint.set_left_margin(3);
+ var buffer = fingerprint.get_buffer();
+ buffer.set_text(colonize(trust_anchor.server_cert, 16), -1);
+ fingerprint.wrap_mode = Gtk.WrapMode.WORD_CHAR;
+
+ set_atk_relation(fingerprint_label, fingerprint, Atk.RelationType.LABEL_FOR);
+
+ var fingerprint_width_constraint = new ScrolledWindow(null, null);
+ fingerprint_width_constraint.set_policy(PolicyType.NEVER, PolicyType.NEVER);
+ fingerprint_width_constraint.set_shadow_type(ShadowType.IN);
+ fingerprint_width_constraint.set_size_request(300, 60);
+ fingerprint_width_constraint.add_with_viewport(fingerprint);
+
+ var vbox = new VBox(false, 0);
+ vbox.pack_start(fingerprint_label, true, true, 2);
+ vbox.pack_start(fingerprint_width_constraint, true, true, 2);
+ return vbox;
+}
+
+ // Yeah, it doesn't mean "colonize" the way you might think... :-)
+internal static string colonize(string input, int bytes_per_line) {
+ return_if_fail(input.length % 2 == 0);
+
+ string result = "";
+ int i = 0;
+ int line_bytes = 0;
+ while (i < input.length) {
+ if (line_bytes == bytes_per_line) {
+ result += "\n";
+ line_bytes = 0;
+ }
+ else if (i > 0) {
+ result += ":";
+ }
+ result += input[i : i + 2];
+ i += 2;
+ line_bytes++;
+ }
+ return result;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011-2016, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+*/
+using Gtk;
+
+static const string GROUP_NAME="WarningDialogs";
+
+// MessageDialog doesn't allow subclassing, so we merely wrap the
+// constructor for it the dialog, and then run it, returning the result.
+class WarningDialog
+{
+ private static MoonshotLogger _logger = null;
+ private static MoonshotLogger logger()
+ {
+ if (_logger == null) {
+ _logger = get_logger("WarningDialog");
+ }
+ return _logger;
+ }
+
+ public static bool confirm(Window parent, string message, string dialog_name)
+ {
+
+ if (get_bool_setting(GROUP_NAME, dialog_name, false))
+ {
+ logger().trace(@"confirm: Settings group $GROUP_NAME has 'true' for key $dialog_name; skipping dialog and returning true.");
+ return true;
+ }
+
+ Gdk.Color white = make_color(65535, 65535, 65535);
+
+ MessageDialog dialog = new Gtk.MessageDialog(parent,
+ Gtk.DialogFlags.DESTROY_WITH_PARENT,
+ Gtk.MessageType.WARNING,
+ Gtk.ButtonsType.YES_NO,
+ "");
+
+ var content_area = dialog.get_content_area();
+ CheckButton remember_checkbutton = null;
+
+ if (dialog_name != null && dialog_name != "")
+ {
+ remember_checkbutton = new CheckButton.with_label(_("Do not show this message again"));
+ // remember_checkbutton.set_focus_on_click(false);
+ // remember_checkbutton.set_can_focus(false);
+ // remember_checkbutton.has_focus = false;
+ remember_checkbutton.set_receives_default(false);
+ Container action_area = (Container) dialog.get_action_area();
+
+ // This is awful, because it assumes the Yes button is first in the
+ // children (and for that matter, it assumes there are no intermediate
+ // containers.) But searching for "Yes" in the widget text would
+ // cause localization problems.
+ // TODO: Rewrite to use Dialog instead of MessageDialog?
+ var yes_button = action_area.get_children().first().data;
+ yes_button.grab_default();
+ yes_button.grab_focus();
+
+// Not sure if 0.26 is the minimum for MessageDialog.get_message_area. 0.16 sure isn't :-(
+#if VALA_0_26
+ var message_area = dialog.get_message_area();
+ ((Box)message_area).pack_start(remember_checkbutton, false, false, 12);
+#else
+ HBox hbox = new HBox(false, 0);
+ hbox.pack_start(new HBox(false, 0), true, true, 20);
+ hbox.pack_start(remember_checkbutton, false, false, 12);
+ ((Box)content_area).pack_start(hbox, true, true, 12);
+#endif
+ }
+
+ // dialog.set_modal(true);
+ dialog.set_title(_("Warning"));
+ dialog.modify_bg(StateType.NORMAL, white);
+
+ // ((Box) content_area).set_spacing(12);
+ content_area.modify_bg(StateType.NORMAL, white);
+
+ content_area.show_all();
+
+ dialog.set_markup(message);
+
+ var ret = dialog.run();
+
+ if (ret == Gtk.ResponseType.YES && remember_checkbutton != null && remember_checkbutton.active)
+ {
+ set_bool_setting(GROUP_NAME, dialog_name, true);
+ }
+
+ dialog.destroy();
+ return (ret == Gtk.ResponseType.YES);
+ }
+}
/*
- * Copyright (c) 2011-2014, JANET(UK)
+ * Copyright (c) 2011-2016, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
public static int main(string[] args)
{
- logger = new MoonshotLogger("WebProvisioning");
+ logger = new MoonshotLogger("WebProvisioning (WebpParser)");
int arg_index = -1;
int force_flat_file_store = 0;
/* use temp arrays to workaround centos array property bug */
var rules = card.rules;
- var services = card.services;
+ string[] svcs = new string[card.services.size];
+ for (int i = 0; i < card.services.size; i++) {
+ svcs[i] = card.services[i];
+ }
+
if (rules.length > 0)
{
int i = 0;
card.issuer,
rules_patterns,
rules_always_confirm,
- services,
+ svcs,
card.trust_anchor.ca_cert,
card.trust_anchor.subject,
card.trust_anchor.subject_alt,
<identities>
+ <identity>
+ <display-name>A Simple Card</display-name>
+ <user>user5</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ </services>
+ </identity>
+
<identity>
<display-name>Unique Name</display-name>
<user>user1</user>
<password></password>
- <realm>foo.baz</realm>
+ <realm>painless-security.com</realm>
<services>
- <service>irc@jabber.project-moonshot.org</service>
- <service>xmpp@jabber.project-moonshot.org</service>
+ <service>irc/painless-security.com</service>
+ <service>xmpp/painless-security.com</service>
</services>
<selection-rules>
<rule>
<always-confirm>true</always-confirm>
</rule>
<rule>
- <pattern>imap@*moonshot.org</pattern>
+ <pattern>imap/*moonshot.org</pattern>
<always-confirm>false</always-confirm>
</rule>
</selection-rules>
<trust-anchor>
- <ca-cert>ABCDEFGHIJKLMNOPQRSTUVWXYZ123455678910</ca-cert>
- <subject>Foo</subject>
- <subject-alt>Bar</subject-alt>
+ <!-- PEM encoded, minus header and footer -->
+ <ca-cert>MIIE9jCCA96gAwIBAgIJAJ6SVDCP6o2nMA0GCSqGSIb3DQEBBQUAMIGaMQswCQYD
+VQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMR
+UGFpbmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFp
+bmxlc3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwg
+SW5jLjAeFw0xNjA4MDExNjIxMDVaFw0xOTExMTQxNjIxMDVaMIGaMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMRUGFp
+bmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFpbmxl
+c3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwgSW5j
+LjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKPiSkw1y6zMJFjnoPjd
+5Bh9EA1NhQcoNxJAtgYEJtpH9a2tfjnXXncXpbIMIfMgv2VKRAxvKb+knCfSCRtU
+PM9i998+ZhJY9o6SSFomlMvdaClauPvBhQvQMmJmp1WINgMUHPpzsGlj04kkl7jw
+iK/oDxp1becikKc10Gr9W03aEJtOaiSqC45zeIgnz9GoQ2tJvz2DDBcddaaT1mSV
+n/lk4ahPC4XaJ08Jn1L6XkVVyDGD38Rwg7r1SFI7ByBFvvQh93Fa48Z7ik0I8s48
+U1euHak2gSJ4zfzLndvGy05qMjhRTlxQu+Rt1g7CS3CLcJqqYzWNrEJWpD8Wn7iA
+MIUCAwEAAaOCATswggE3MB0GA1UdDgQWBBR1qlvY7r2DqhHu5s+sCUPeqBcQuzCB
+zwYDVR0jBIHHMIHEgBR1qlvY7r2DqhHu5s+sCUPeqBcQu6GBoKSBnTCBmjELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAk1BMQ8wDQYDVQQHEwZNYWxkZW4xGjAYBgNVBAoT
+EVBhaW5sZXNzIFNlY3VyaXR5MS8wLQYJKoZIhvcNAQkBFiBwb3N0bWFzdGVyQHBh
+aW5sZXNzLXNlY3VyaXR5LmNvbTEgMB4GA1UEAxMXUGFpbmxlc3MgU2VjdXJpdHks
+IEluYy6CCQCeklQwj+qNpzAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeG
+JWh0dHA6Ly93d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcN
+AQEFBQADggEBAB6J5Zxvq96SdIsfEajqU+pANBiA2VTZCpxfIMAKz8KfyzWzFvCM
+8epvYDliyOjw1zR9cYxhQqOcbPHrjLXheVvCePd3jCUOv+tt1Nw2gS2DiMuq37DO
+BZOTlPJ3m2NnvJVO3NjB2I+Pk9v3YlG6mkiVc9dNWgO20SqT2Y+KvHqA5Of8Cb/s
+uIBftctvGpIyEnqSmU7KB0nhIWe65Bsu60hjHHfX1qhJE7qGKbqNaHujssQ/SBXJ
+g7HUhtywv8z3TFoYW0MoBpKGM2Ojc9kQ8f0rYvUKTiD1UfjQoll/Io5xwKy7FXtn
+musuCxXeWkqDtw0clWg6vkf5Tb9v/JQ2PW0=</ca-cert>
+ <subject>Painless Security Server Certificate</subject>
<!-- Or alternatively -->
- <server-cert>ABCDEFGHIJKLMNOPQRSTUVWXYZ123455678910</server-cert>
+ <server-cert></server-cert>
</trust-anchor>
</identity>
<identity>
<display-name>Another Unique Name</display-name>
<user>user2</user>
<password></password>
- <realm>foo.bar</realm>
+ <realm>painless-security.com</realm>
<services>
- <service>irc@jabber.project-moonshot.org</service>
- <service>email@project-moonshot.org</service>
+ <service>irc/painless-security.com</service>
+ <service>email/painless-security.com</service>
</services>
<selection-rules>
<rule>
- <pattern>*@project-moonshot.org</pattern>
+ <pattern>*/painless-security.com</pattern>
<always-confirm>true</always-confirm>
</rule>
</selection-rules>
<trust-anchor>
- <ca-cert>ABCDEFGHIJKLMNOPQRSTUVWXYZ123455678910</ca-cert>
- <subject>Foo</subject>
- <subject-alt>Bar</subject-alt>
- <!-- Or alternatively -->
- <server-cert>ABCDEFGHIJKLMNOPQRSTUVWXYZ123455678910</server-cert>
+ <ca-cert>
+ <!-- DER format, base64-encoded -->MIIE9jCCA96gAwIBAgIJAJ6SVDCP6o2nMA0GCSqGSIb3DQEBBQUAMIGaMQswCQYDVQQGEwJVUzEL
+MAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMRUGFpbmxlc3MgU2VjdXJpdHkx
+LzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFpbmxlc3Mtc2VjdXJpdHkuY29tMSAwHgYDVQQD
+ExdQYWlubGVzcyBTZWN1cml0eSwgSW5jLjAeFw0xNjA4MDExNjIxMDVaFw0xOTExMTQxNjIxMDVa
+MIGaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTUExDzANBgNVBAcTBk1hbGRlbjEaMBgGA1UEChMR
+UGFpbmxlc3MgU2VjdXJpdHkxLzAtBgkqhkiG9w0BCQEWIHBvc3RtYXN0ZXJAcGFpbmxlc3Mtc2Vj
+dXJpdHkuY29tMSAwHgYDVQQDExdQYWlubGVzcyBTZWN1cml0eSwgSW5jLjCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKPiSkw1y6zMJFjnoPjd5Bh9EA1NhQcoNxJAtgYEJtpH9a2tfjnX
+XncXpbIMIfMgv2VKRAxvKb+knCfSCRtUPM9i998+ZhJY9o6SSFomlMvdaClauPvBhQvQMmJmp1WI
+NgMUHPpzsGlj04kkl7jwiK/oDxp1becikKc10Gr9W03aEJtOaiSqC45zeIgnz9GoQ2tJvz2DDBcd
+daaT1mSVn/lk4ahPC4XaJ08Jn1L6XkVVyDGD38Rwg7r1SFI7ByBFvvQh93Fa48Z7ik0I8s48U1eu
+Hak2gSJ4zfzLndvGy05qMjhRTlxQu+Rt1g7CS3CLcJqqYzWNrEJWpD8Wn7iAMIUCAwEAAaOCATsw
+ggE3MB0GA1UdDgQWBBR1qlvY7r2DqhHu5s+sCUPeqBcQuzCBzwYDVR0jBIHHMIHEgBR1qlvY7r2D
+qhHu5s+sCUPeqBcQu6GBoKSBnTCBmjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMQ8wDQYDVQQH
+EwZNYWxkZW4xGjAYBgNVBAoTEVBhaW5sZXNzIFNlY3VyaXR5MS8wLQYJKoZIhvcNAQkBFiBwb3N0
+bWFzdGVyQHBhaW5sZXNzLXNlY3VyaXR5LmNvbTEgMB4GA1UEAxMXUGFpbmxlc3MgU2VjdXJpdHks
+IEluYy6CCQCeklQwj+qNpzAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93
+d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAB6J5Zxvq96S
+dIsfEajqU+pANBiA2VTZCpxfIMAKz8KfyzWzFvCM8epvYDliyOjw1zR9cYxhQqOcbPHrjLXheVvC
+ePd3jCUOv+tt1Nw2gS2DiMuq37DOBZOTlPJ3m2NnvJVO3NjB2I+Pk9v3YlG6mkiVc9dNWgO20SqT
+2Y+KvHqA5Of8Cb/suIBftctvGpIyEnqSmU7KB0nhIWe65Bsu60hjHHfX1qhJE7qGKbqNaHujssQ/
+SBXJg7HUhtywv8z3TFoYW0MoBpKGM2Ojc9kQ8f0rYvUKTiD1UfjQoll/Io5xwKy7FXtnmusuCxXe
+WkqDtw0clWg6vkf5Tb9v/JQ2PW0=
+</ca-cert>
+ <subject>Painless Security Server Certificate</subject>
</trust-anchor>
</identity>
<identity>
<display-name>Yet Another Unique Name</display-name>
<user>user3</user>
<password></password>
- <realm>foo.com</realm>
+ <realm>painless-security.com</realm>
<services>
- <service>irc@jabber.project-moonshot.org</service>
- <service>email@project-moonshot.org</service>
+ <service>irc/painless-security.com</service>
+ <service>email/painless-security.com</service>
</services>
<trust-anchor>
- <ca-cert>ABCDEFGHIJKLMNOPQRSTUVWXYZ123455678910</ca-cert>
- <subject>Foo</subject>
- <subject-alt>Bar</subject-alt>
- <!-- Or alternatively -->
- <server-cert>ABCDEFGHIJKLMNOPQRSTUVWXYZ123455678910</server-cert>
+ <server-cert>3838E17EC9A2A06D7B6030E3C5727E3466EAB4BB4159DCE7CF6297ADAFC8A56F</server-cert>
+ </trust-anchor>
+ </identity>
+ <identity>
+ <display-name>A Not Really Unique Name</display-name>
+ <user>user4</user>
+ <password></password>
+ <realm>painless-security.com</realm>
+ <services>
+ <service>ssh/painless-security.com</service>
+ <service>email/painless-security.com</service>
+ </services>
+ <trust-anchor>
+ <server-cert>3838E17EC9A2A06D7B6030E3C5727E3466EAB4BB4159DCE7CF6297ADAFC8A56F</server-cert>
</trust-anchor>
</identity>
+
</identities>