summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-08-24 16:24:40 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-08-24 16:24:40 +0300
commit42bb54ff55ae6e2e2c6bf8a5581d14c1289f0234 (patch)
tree9a4cd949264e98bf47032199779ee27bd1193f58
parent455a635080a1c1c4b164af3060836f0d8c1b3c1c (diff)
SidebarWidget: List identities as sidebar items
-rw-r--r--src/app.c8
-rw-r--r--src/gmcerts.c17
-rw-r--r--src/gmcerts.h14
-rw-r--r--src/ui/sidebarwidget.c62
-rw-r--r--src/ui/util.c8
-rw-r--r--src/ui/widget.c2
-rw-r--r--src/ui/window.c17
7 files changed, 105 insertions, 23 deletions
diff --git a/src/app.c b/src/app.c
index 31be06fd..5bcbfc29 100644
--- a/src/app.c
+++ b/src/app.c
@@ -537,7 +537,8 @@ iDocumentWidget *newTab_App(const iDocumentWidget *duplicateOf) {
537} 537}
538 538
539static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) { 539static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {
540 if (equal_Command(cmd, "ident.accept") || equal_Command(cmd, "cancel")) { 540 iApp *d = &app_;
541 if (equal_Command(cmd, "ident.accept") || equal_Command(cmd, "cancel")) {
541 if (equal_Command(cmd, "ident.accept")) { 542 if (equal_Command(cmd, "ident.accept")) {
542 const iString *commonName = text_InputWidget (findChild_Widget(dlg, "ident.common")); 543 const iString *commonName = text_InputWidget (findChild_Widget(dlg, "ident.common"));
543 const iString *userId = text_InputWidget (findChild_Widget(dlg, "ident.userid")); 544 const iString *userId = text_InputWidget (findChild_Widget(dlg, "ident.userid"));
@@ -584,7 +585,10 @@ static iBool handleIdentityCreationCommands_(iWidget *dlg, const char *cmd) {
584 } 585 }
585 } 586 }
586 } 587 }
587 588 /* The input seems fine. */
589 newIdentity_GmCerts(d->certs, isTemp ? temporary_GmIdentityFlag : 0,
590 until, commonName, userId, organization, country);
591 postCommand_App("idents.changed");
588 } 592 }
589 destroy_Widget(dlg); 593 destroy_Widget(dlg);
590 return iTrue; 594 return iTrue;
diff --git a/src/gmcerts.c b/src/gmcerts.c
index e13e9a8d..2624eb4d 100644
--- a/src/gmcerts.c
+++ b/src/gmcerts.c
@@ -125,6 +125,7 @@ static iBool isValid_GmIdentity_(const iGmIdentity *d) {
125static void setCertificate_GmIdentity_(iGmIdentity *d, iTlsCertificate *cert) { 125static void setCertificate_GmIdentity_(iGmIdentity *d, iTlsCertificate *cert) {
126 delete_TlsCertificate(d->cert); 126 delete_TlsCertificate(d->cert);
127 d->cert = cert; 127 d->cert = cert;
128 set_Block(&d->fingerprint, collect_Block(fingerprint_TlsCertificate(cert)));
128} 129}
129 130
130static const iString *readFile_(const iString *path) { 131static const iString *readFile_(const iString *path) {
@@ -249,7 +250,6 @@ static void loadIdentityFromCertificate_GmCerts_(iGmCerts *d, const iString *crt
249 iGmIdentity *ident = findIdentity_GmCerts_(d, finger); 250 iGmIdentity *ident = findIdentity_GmCerts_(d, finger);
250 if (!ident) { 251 if (!ident) {
251 ident = new_GmIdentity(); 252 ident = new_GmIdentity();
252 set_Block(&ident->fingerprint, finger);
253 iDate today; 253 iDate today;
254 initCurrent_Date(&today); 254 initCurrent_Date(&today);
255 set_String(&ident->notes, collect_String(format_Date(&today, "Imported on %b %d, %Y"))); 255 set_String(&ident->notes, collect_String(format_Date(&today, "Imported on %b %d, %Y")));
@@ -387,9 +387,9 @@ iGmIdentity *newIdentity_GmCerts(iGmCerts *d, int flags, iDate validUntil, const
387 const iTlsCertificateName names[] = { 387 const iTlsCertificateName names[] = {
388 { issuerCommonName_TlsCertificateNameType, collectNewCStr_String("fi.skyjake.Lagrange") }, 388 { issuerCommonName_TlsCertificateNameType, collectNewCStr_String("fi.skyjake.Lagrange") },
389 { subjectCommonName_TlsCertificateNameType, commonName }, 389 { subjectCommonName_TlsCertificateNameType, commonName },
390 { subjectUserId_TlsCertificateNameType, userId }, 390 { subjectUserId_TlsCertificateNameType, !isEmpty_String(userId) ? userId : NULL },
391 { subjectOrganization_TlsCertificateNameType, org }, 391 { subjectOrganization_TlsCertificateNameType, !isEmpty_String(org) ? org : NULL },
392 { subjectCountry_TlsCertificateNameType, country }, 392 { subjectCountry_TlsCertificateNameType, !isEmpty_String(country) ? country : NULL },
393 { 0, NULL } 393 { 0, NULL }
394 }; 394 };
395 iGmIdentity *id = new_GmIdentity(); 395 iGmIdentity *id = new_GmIdentity();
@@ -398,17 +398,22 @@ iGmIdentity *newIdentity_GmCerts(iGmCerts *d, int flags, iDate validUntil, const
398 if (~flags & temporary_GmIdentityFlag) { 398 if (~flags & temporary_GmIdentityFlag) {
399 const char *finger = cstrCollect_String(hexEncode_Block(&id->fingerprint)); 399 const char *finger = cstrCollect_String(hexEncode_Block(&id->fingerprint));
400 if (!writeTextFile_( 400 if (!writeTextFile_(
401 collect_String(concatCStr_Path(&d->saveDir, format_CStr("%s.crt", finger))), 401 collect_String(concatCStr_Path(&d->saveDir, format_CStr("idents/%s.crt", finger))),
402 collect_String(pem_TlsCertificate(id->cert)))) { 402 collect_String(pem_TlsCertificate(id->cert)))) {
403 delete_GmIdentity(id); 403 delete_GmIdentity(id);
404 return NULL; 404 return NULL;
405 } 405 }
406 if (!writeTextFile_( 406 if (!writeTextFile_(
407 collect_String(concatCStr_Path(&d->saveDir, format_CStr("%s.key", finger))), 407 collect_String(concatCStr_Path(&d->saveDir, format_CStr("idents/%s.key", finger))),
408 collect_String(privateKeyPem_TlsCertificate(id->cert)))) { 408 collect_String(privateKeyPem_TlsCertificate(id->cert)))) {
409 delete_GmIdentity(id); 409 delete_GmIdentity(id);
410 return NULL; 410 return NULL;
411 } 411 }
412 } 412 }
413 pushBack_PtrArray(&d->idents, id);
413 return id; 414 return id;
414} 415}
416
417const iPtrArray *identities_GmCerts(const iGmCerts *d) {
418 return &d->idents;
419}
diff --git a/src/gmcerts.h b/src/gmcerts.h
index 6f34e5dd..32a383be 100644
--- a/src/gmcerts.h
+++ b/src/gmcerts.h
@@ -22,6 +22,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#pragma once 23#pragma once
24 24
25#include <the_Foundation/ptrarray.h>
25#include <the_Foundation/tlsrequest.h> 26#include <the_Foundation/tlsrequest.h>
26 27
27iDeclareType(GmIdentity) 28iDeclareType(GmIdentity)
@@ -49,6 +50,19 @@ iBool checkTrust_GmCerts (iGmCerts *, iRangecc domain, const
49 50
50const iGmIdentity * identityForUrl_GmCerts (const iGmCerts *, const iString *url); 51const iGmIdentity * identityForUrl_GmCerts (const iGmCerts *, const iString *url);
51 52
53/**
54 * Create a new self-signed TLS client certificate for identifying the user.
55 * @a commonName and the other name parameters are inserted in the subject field
56 * of the certificate.
57 *
58 * @param flags Identity flags. A temporary identity is not saved persistently and
59 * will be erased when the application is shut down.
60 * @param validUntil Expiration date. Must be in the future.
61 *
62 * @returns Created identity. GmCerts retains ownership of returned object.
63 */
52iGmIdentity * newIdentity_GmCerts (iGmCerts *, int flags, iDate validUntil, 64iGmIdentity * newIdentity_GmCerts (iGmCerts *, int flags, iDate validUntil,
53 const iString *commonName, const iString *userId, 65 const iString *commonName, const iString *userId,
54 const iString *org, const iString *country); 66 const iString *org, const iString *country);
67
68const iPtrArray * identities_GmCerts (const iGmCerts *);
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index 82efb04e..aa2e185d 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -22,11 +22,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
22 22
23#include "sidebarwidget.h" 23#include "sidebarwidget.h"
24 24
25#include "../gmdocument.h"
26#include "app.h" 25#include "app.h"
27#include "bookmarks.h" 26#include "bookmarks.h"
28#include "command.h" 27#include "command.h"
29#include "documentwidget.h" 28#include "documentwidget.h"
29#include "gmcerts.h"
30#include "gmdocument.h"
30#include "inputwidget.h" 31#include "inputwidget.h"
31#include "labelwidget.h" 32#include "labelwidget.h"
32#include "paint.h" 33#include "paint.h"
@@ -216,6 +217,33 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) {
216 }, 6); 217 }, 6);
217 break; 218 break;
218 } 219 }
220 case identities_SidebarMode: {
221 iConstForEach(PtrArray, i, identities_GmCerts(certs_App())) {
222 const iGmIdentity *ident = i.ptr;
223 /* icon, common name, used URLs, expiration, isTemp, free-form notes */
224 iSidebarItem item;
225 init_SidebarItem(&item);
226 item.icon = ident->icon;
227 set_String(&item.label, collect_String(subject_TlsCertificate(ident->cert)));
228 iDate until;
229 validUntil_TlsCertificate(ident->cert, &until);
230 set_String(
231 &item.meta,
232 collectNewFormat_String(
233 "%s \u2014 %s\n%s",
234 isEmpty_SortedArray(&ident->useUrls)
235 ? "Not used"
236 : format_CStr("Used on %zu URLs", size_SortedArray(&ident->useUrls)),
237 ident->flags & temporary_GmIdentityFlag
238 ? "Temporary"
239 : cstrCollect_String(format_Date(&until, "Expires %b %d, %Y")),
240 cstr_String(&ident->notes)));
241 pushBack_Array(&d->items, &item);
242 }
243 /* menu: set icon, edit notes, view urls, reveal files, delete, activate on this page,
244 * deactivate on this page, deactivate everywhere */
245 break;
246 }
219 default: 247 default:
220 break; 248 break;
221 } 249 }
@@ -247,7 +275,7 @@ void setMode_SidebarWidget(iSidebarWidget *d, enum iSidebarMode mode) {
247 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) { 275 for (enum iSidebarMode i = 0; i < max_SidebarMode; i++) {
248 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode); 276 setFlags_Widget(as_Widget(d->modeButtons[i]), selected_WidgetFlag, i == d->mode);
249 } 277 }
250 const float heights[max_SidebarMode] = { 1.333f, 1.333f, 2.5f, 1.2f }; 278 const float heights[max_SidebarMode] = { 1.333f, 1.333f, 3.0f, 1.2f };
251 d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId); 279 d->itemHeight = heights[mode] * lineHeight_Text(uiContent_FontId);
252 invalidate_SidebarWidget_(d); 280 invalidate_SidebarWidget_(d);
253 /* Restore previous scroll position. */ 281 /* Restore previous scroll position. */
@@ -529,7 +557,10 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev)
529 } 557 }
530 return iTrue; 558 return iTrue;
531 } 559 }
532 else if (equal_Command(cmd, "bookmarks.changed")) { 560 else if (equal_Command(cmd, "bookmarks.changed") && d->mode == bookmarks_SidebarMode) {
561 updateItems_SidebarWidget_(d);
562 }
563 else if (equal_Command(cmd, "idents.changed") && d->mode == identities_SidebarMode) {
533 updateItems_SidebarWidget_(d); 564 updateItems_SidebarWidget_(d);
534 } 565 }
535 else if (equal_Command(cmd, "history.delete")) { 566 else if (equal_Command(cmd, "history.delete")) {
@@ -661,6 +692,9 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
661 const iSidebarItem *item = constAt_Array(&d->items, i); 692 const iSidebarItem *item = constAt_Array(&d->items, i);
662 const iRect itemRect = { pos, init_I2(width_Rect(bufBounds), d->itemHeight) }; 693 const iRect itemRect = { pos, init_I2(width_Rect(bufBounds), d->itemHeight) };
663 const iBool isHover = (d->hoverItem == i); 694 const iBool isHover = (d->hoverItem == i);
695 const int iconColor =
696 isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId)
697 : uiIcon_ColorId;
664 setClip_Paint(&p, intersect_Rect(itemRect, bufBounds)); 698 setClip_Paint(&p, intersect_Rect(itemRect, bufBounds));
665 if (isHover && !item->isSeparator) { 699 if (isHover && !item->isSeparator) {
666 fillRect_Paint(&p, 700 fillRect_Paint(&p,
@@ -691,8 +725,7 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
691 font, 725 font,
692 iconArea, 726 iconArea,
693 iTrue, 727 iTrue,
694 isHover ? (isPressing ? uiTextPressed_ColorId : uiIconHover_ColorId) 728 iconColor,
695 : uiIcon_ColorId,
696 "%s", 729 "%s",
697 cstr_String(&str)); 730 cstr_String(&str));
698 deinit_String(&str); 731 deinit_String(&str);
@@ -737,6 +770,25 @@ static void draw_SidebarWidget_(const iSidebarWidget *d) {
737 } 770 }
738 iEndCollect(); 771 iEndCollect();
739 } 772 }
773 else if (d->mode == identities_SidebarMode) {
774 const int fg = isHover ? (isPressing ? uiTextPressed_ColorId
775 : uiTextFramelessHover_ColorId)
776 : uiText_ColorId;
777 iString icon;
778 initUnicodeN_String(&icon, &item->icon, 1);
779 drawRange_Text(font, add_I2(topLeft_Rect(itemRect), init_I2(3 * gap_UI, 0)),
780 iconColor, range_String(&icon));
781 deinit_String(&icon);
782 drawRange_Text(font, add_I2(topLeft_Rect(itemRect), init_I2(10 * gap_UI, 0)),
783 fg, range_String(&item->label));
784 drawRange_Text(
785 font,
786 add_I2(topLeft_Rect(itemRect), init_I2(3 * gap_UI, lineHeight_Text(font))),
787 isHover
788 ? (isPressing ? uiTextPressed_ColorId : uiTextFramelessHover_ColorId)
789 : uiAnnotation_ColorId,
790 range_String(&item->meta));
791 }
740 unsetClip_Paint(&p); 792 unsetClip_Paint(&p);
741 pos.y += d->itemHeight; 793 pos.y += d->itemHeight;
742 } 794 }
diff --git a/src/ui/util.c b/src/ui/util.c
index b3178e34..e6067ab9 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -689,9 +689,11 @@ iWidget *makeQuestion_Widget(const char *title,
689} 689}
690 690
691void setToggle_Widget(iWidget *d, iBool active) { 691void setToggle_Widget(iWidget *d, iBool active) {
692 setFlags_Widget(d, selected_WidgetFlag, active); 692 if (d) {
693 updateText_LabelWidget((iLabelWidget *) d, 693 setFlags_Widget(d, selected_WidgetFlag, active);
694 collectNewFormat_String("%s", isSelected_Widget(d) ? "YES" : "NO")); 694 updateText_LabelWidget((iLabelWidget *) d,
695 collectNewFormat_String("%s", isSelected_Widget(d) ? "YES" : "NO"));
696 }
695} 697}
696 698
697static iBool toggleHandler_(iWidget *d, const char *cmd) { 699static iBool toggleHandler_(iWidget *d, const char *cmd) {
diff --git a/src/ui/widget.c b/src/ui/widget.c
index f187bb82..b5ea3b0f 100644
--- a/src/ui/widget.c
+++ b/src/ui/widget.c
@@ -637,7 +637,7 @@ iBool isHover_Widget(const iWidget *d) {
637} 637}
638 638
639iBool isSelected_Widget(const iWidget *d) { 639iBool isSelected_Widget(const iWidget *d) {
640 return (d->flags & selected_WidgetFlag) != 0; 640 return d && (d->flags & selected_WidgetFlag) != 0;
641} 641}
642 642
643iBool equalWidget_Command(const char *cmd, const iWidget *widget, const char *checkCommand) { 643iBool equalWidget_Command(const char *cmd, const iWidget *widget, const char *checkCommand) {
diff --git a/src/ui/window.c b/src/ui/window.c
index fad87f08..709fc0e0 100644
--- a/src/ui/window.c
+++ b/src/ui/window.c
@@ -102,6 +102,8 @@ static const iMenuItem navMenuItems[] = {
102 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" }, 102 { "Reset Zoom", SDLK_0, KMOD_PRIMARY, "zoom.set arg:100" },
103 { "---", 0, 0, NULL }, 103 { "---", 0, 0, NULL },
104 { "Preferences...", SDLK_COMMA, KMOD_PRIMARY, "preferences" }, 104 { "Preferences...", SDLK_COMMA, KMOD_PRIMARY, "preferences" },
105 { "Help", 0, 0, "!open url:about:help" },
106 { "Release Notes", 0, 0, "!open url:about:version" },
105 { "---", 0, 0, NULL }, 107 { "---", 0, 0, NULL },
106 { "Quit Lagrange", 'q', KMOD_PRIMARY, "quit" } 108 { "Quit Lagrange", 'q', KMOD_PRIMARY, "quit" }
107}; 109};
@@ -121,10 +123,6 @@ static const iMenuItem editMenuItems[] = {
121 { "Bookmark This Page...", SDLK_d, KMOD_PRIMARY, "bookmark.add" }, 123 { "Bookmark This Page...", SDLK_d, KMOD_PRIMARY, "bookmark.add" },
122}; 124};
123 125
124static const iMenuItem identityMenuItems[] = {
125 { "New Identity...", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" },
126};
127
128static const iMenuItem viewMenuItems[] = { 126static const iMenuItem viewMenuItems[] = {
129 { "Show Bookmarks", '1', KMOD_PRIMARY, "sidebar.mode arg:0 show:1" }, 127 { "Show Bookmarks", '1', KMOD_PRIMARY, "sidebar.mode arg:0 show:1" },
130 { "Show History", '2', KMOD_PRIMARY, "sidebar.mode arg:1 show:1" }, 128 { "Show History", '2', KMOD_PRIMARY, "sidebar.mode arg:1 show:1" },
@@ -147,6 +145,10 @@ static const iMenuItem helpMenuItems[] = {
147}; 145};
148#endif 146#endif
149 147
148static const iMenuItem identityMenuItems[] = {
149 { "New Identity...", SDLK_n, KMOD_PRIMARY | KMOD_SHIFT, "ident.new" },
150};
151
150static const char *reloadCStr_ = "\U0001f503"; 152static const char *reloadCStr_ = "\U0001f503";
151static const char *stopCStr_ = uiTextCaution_ColorEscape "\U0001f310"; 153static const char *stopCStr_ = uiTextCaution_ColorEscape "\U0001f310";
152 154
@@ -312,8 +314,11 @@ static void setupUserInterface_Window(iWindow *d) {
312 setId_Widget( 314 setId_Widget(
313 addChild_Widget(navBar, iClob(newIcon_LabelWidget(reloadCStr_, 0, 0, "navigate.reload"))), 315 addChild_Widget(navBar, iClob(newIcon_LabelWidget(reloadCStr_, 0, 0, "navigate.reload"))),
314 "reload"); 316 "reload");
315 addChild_Widget(navBar, iClob(newIcon_LabelWidget("\U0001f464", 0, 0, "cert.client"))); 317 iLabelWidget *idMenu =
316 318 makeMenuButton_LabelWidget("\U0001f464", identityMenuItems, iElemCount(identityMenuItems));
319 setAlignVisually_LabelWidget(idMenu, iTrue);
320 addChild_Widget(navBar, iClob(idMenu));
321 //addChild_Widget(navBar, iClob(newIcon_LabelWidget("\U0001f464", 0, 0, "cert.client")));
317#if !defined (iHaveNativeMenus) 322#if !defined (iHaveNativeMenus)
318 iLabelWidget *navMenu = 323 iLabelWidget *navMenu =
319 makeMenuButton_LabelWidget("\U0001d362", navMenuItems, iElemCount(navMenuItems)); 324 makeMenuButton_LabelWidget("\U0001d362", navMenuItems, iElemCount(navMenuItems));