xref: /haiku/src/servers/keystore/KeyRequestWindow.cpp (revision f73f5d4c42a01ece688cbb57b5d332cc0f68b2c6)
1 /*
2  * Copyright 2012, Michael Lotz, mmlr@mlotz.ch. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "KeyRequestWindow.h"
8 
9 #include <Button.h>
10 #include <CheckBox.h>
11 #include <GridLayout.h>
12 #include <GridView.h>
13 #include <GroupLayout.h>
14 #include <GroupView.h>
15 #include <Key.h>
16 #include <MenuField.h>
17 #include <MenuItem.h>
18 #include <NetworkDevice.h>
19 #include <PopUpMenu.h>
20 #include <SpaceLayoutItem.h>
21 #include <StringView.h>
22 #include <TextControl.h>
23 #include <TextView.h>
24 #include <View.h>
25 
26 #include <new>
27 
28 
29 static const uint32 kMessageCancel = 'btcl';
30 static const uint32 kMessageUnlock = 'btul';
31 
32 
33 class KeyRequestView : public BView {
34 public:
35 	KeyRequestView()
36 		:
37 		BView("KeyRequestView", B_WILL_DRAW),
38 		fPassword(NULL)
39 	{
40 		SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
41 
42 		BGroupLayout* rootLayout = new(std::nothrow) BGroupLayout(B_VERTICAL);
43 		if (rootLayout == NULL)
44 			return;
45 
46 		SetLayout(rootLayout);
47 
48 		BGridView* controls = new(std::nothrow) BGridView();
49 		if (controls == NULL)
50 			return;
51 
52 		BGridLayout* layout = controls->GridLayout();
53 
54 		float inset = ceilf(be_plain_font->Size() * 0.7);
55 		rootLayout->SetInsets(inset, inset, inset, inset);
56 		rootLayout->SetSpacing(inset);
57 		layout->SetSpacing(inset, inset);
58 
59 		BStringView* label = new(std::nothrow) BStringView("keyringLabel",
60 			"Keyring:");
61 		if (label == NULL)
62 			return;
63 
64 		int32 row = 0;
65 		layout->AddView(label, 0, row);
66 
67 		fKeyringName = new(std::nothrow) BStringView("keyringName", "");
68 		if (fKeyringName == NULL)
69 			return;
70 
71 		layout->AddView(fKeyringName, 1, row++);
72 
73 		fPassword = new(std::nothrow) BTextControl("Password:", "", NULL);
74 		if (fPassword == NULL)
75 			return;
76 
77 		BLayoutItem* layoutItem = fPassword->CreateTextViewLayoutItem();
78 		layoutItem->SetExplicitMinSize(BSize(fPassword->StringWidth(
79 				"0123456789012345678901234567890123456789") + inset,
80 			B_SIZE_UNSET));
81 
82 		layout->AddItem(fPassword->CreateLabelLayoutItem(), 0, row);
83 		layout->AddItem(layoutItem, 1, row++);
84 
85 		BGroupView* buttons = new(std::nothrow) BGroupView(B_HORIZONTAL);
86 		if (buttons == NULL)
87 			return;
88 
89 		fCancelButton = new(std::nothrow) BButton("Cancel",
90 			new BMessage(kMessageCancel));
91 		buttons->GroupLayout()->AddView(fCancelButton);
92 
93 		buttons->GroupLayout()->AddItem(BSpaceLayoutItem::CreateGlue());
94 
95 		fUnlockButton = new(std::nothrow) BButton("Unlock",
96 			new BMessage(kMessageUnlock));
97 		buttons->GroupLayout()->AddView(fUnlockButton);
98 
99 		BTextView* message = new(std::nothrow) BTextView("message");
100 		message->SetText("An application wants to access the keyring below, "
101 			"but it is locked with a passphrase. Please enter the passphrase "
102 			"to unlock the keyring.\n"
103 			"If you unlock the keyring, it stays unlocked until the system is "
104 			"shut down or the keyring is manually locked again.\n"
105 			"If you cancel this dialog the keyring will remain locked.");
106 		message->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
107 		rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
108 		message->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor);
109 		message->MakeEditable(false);
110 		message->MakeSelectable(false);
111 		message->SetWordWrap(true);
112 
113 		rootLayout->AddView(message);
114 		rootLayout->AddView(controls);
115 		rootLayout->AddView(buttons);
116 	}
117 
118 	virtual void
119 	AttachedToWindow()
120 	{
121 		fCancelButton->SetTarget(Window());
122 		fUnlockButton->SetTarget(Window());
123 		fUnlockButton->MakeDefault(true);
124 		fPassword->MakeFocus();
125 	}
126 
127 	void
128 	SetUp(const BString& keyringName)
129 	{
130 		fKeyringName->SetText(keyringName);
131 	}
132 
133 	status_t
134 	Complete(BMessage& keyMessage)
135 	{
136 		BPasswordKey password(fPassword->Text(), B_KEY_PURPOSE_KEYRING, "");
137 		return password.Flatten(keyMessage);
138 	}
139 
140 private:
141 	BStringView* fKeyringName;
142 	BTextControl* fPassword;
143 	BButton* fCancelButton;
144 	BButton* fUnlockButton;
145 };
146 
147 
148 KeyRequestWindow::KeyRequestWindow()
149 	:
150 	BWindow(BRect(50, 50, 269, 302), "Unlock Keyring",
151 		B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS
152 			| B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
153 	fRequestView(NULL),
154 	fDoneSem(-1),
155 	fResult(B_ERROR)
156 {
157 	fDoneSem = create_sem(0, "keyring unlock dialog");
158 	if (fDoneSem < 0)
159 		return;
160 
161 	BLayout* layout = new(std::nothrow) BGroupLayout(B_HORIZONTAL);
162 	if (layout == NULL)
163 		return;
164 
165 	SetLayout(layout);
166 
167 	fRequestView = new(std::nothrow) KeyRequestView();
168 	if (fRequestView == NULL)
169 		return;
170 
171 	layout->AddView(fRequestView);
172 }
173 
174 
175 KeyRequestWindow::~KeyRequestWindow()
176 {
177 	if (fDoneSem >= 0)
178 		delete_sem(fDoneSem);
179 }
180 
181 
182 void
183 KeyRequestWindow::DispatchMessage(BMessage* message, BHandler* handler)
184 {
185 	int8 key;
186 	if (message->what == B_KEY_DOWN
187 		&& message->FindInt8("byte", 0, &key) == B_OK
188 		&& key == B_ESCAPE) {
189 		PostMessage(kMessageCancel);
190 	}
191 
192 	BWindow::DispatchMessage(message, handler);
193 }
194 
195 
196 void
197 KeyRequestWindow::MessageReceived(BMessage* message)
198 {
199 	switch (message->what) {
200 		case kMessageCancel:
201 		case kMessageUnlock:
202 			fResult = message->what == kMessageUnlock ? B_OK : B_CANCELED;
203 			release_sem(fDoneSem);
204 			return;
205 	}
206 
207 	BWindow::MessageReceived(message);
208 }
209 
210 
211 status_t
212 KeyRequestWindow::RequestKey(const BString& keyringName, BMessage& keyMessage)
213 {
214 	fRequestView->SetUp(keyringName);
215 
216 	CenterOnScreen();
217 	Show();
218 
219 	while (acquire_sem(fDoneSem) == B_INTERRUPTED)
220 		;
221 
222 	status_t result = fResult;
223 	if (result == B_OK)
224 		result = fRequestView->Complete(keyMessage);
225 
226 	LockLooper();
227 	Quit();
228 	return result;
229 }
230