xref: /haiku/src/preferences/screensaver/PasswordWindow.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
1 /*
2  * Copyright 2003-2007, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Phipps
7  *		Jérôme Duval, jerome.duval@free.fr
8  *		Julun <host.haiku@gmx.de>
9  */
10 
11 #include "PasswordWindow.h"
12 
13 
14 #include <Alert.h>
15 #include <Box.h>
16 #include <Button.h>
17 #include <RadioButton.h>
18 #include <Screen.h>
19 #include <TextControl.h>
20 
21 #include <ctype.h>
22 
23 
24 const uint32 kMsgDone = 'done';
25 const uint32 kMsgPasswordTypeChanged = 'pwtp';
26 
27 
28 PasswordWindow::PasswordWindow(ScreenSaverSettings& settings)
29 	: BWindow(BRect(100, 100, 380, 249), "Password Window", B_MODAL_WINDOW_LOOK,
30 		B_MODAL_APP_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_NOT_RESIZABLE),
31 	fSettings(settings)
32 {
33 	_Setup();
34 	Update();
35 
36 	BRect screenFrame = BScreen(B_MAIN_SCREEN_ID).Frame();
37 	BPoint point;
38 	point.x = (screenFrame.Width() - Bounds().Width()) / 2;
39 	point.y = (screenFrame.Height() - Bounds().Height()) / 2;
40 
41 	if (screenFrame.Contains(point))
42 		MoveTo(point);
43 }
44 
45 
46 void
47 PasswordWindow::_Setup()
48 {
49 	BRect bounds = Bounds();
50 	BView* topView = new BView(bounds, "topView", B_FOLLOW_ALL, B_WILL_DRAW);
51 	topView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
52 	AddChild(topView);
53 
54 	bounds.InsetBy(10.0, 10.0);
55 	fUseNetwork = new BRadioButton(bounds, "useNetwork", "Use network password",
56 		new BMessage(kMsgPasswordTypeChanged), B_FOLLOW_NONE);
57 	topView->AddChild(fUseNetwork);
58 	fUseNetwork->ResizeToPreferred();
59 	fUseNetwork->MoveBy(10.0, 0.0);
60 
61 	bounds.OffsetBy(0.0, fUseNetwork->Bounds().Height());
62 	BBox *customBox = new BBox(bounds, "customBox", B_FOLLOW_NONE);
63 	topView->AddChild(customBox);
64 
65 	fUseCustom = new BRadioButton(BRect(), "useCustom", "Use custom password",
66 		new BMessage(kMsgPasswordTypeChanged), B_FOLLOW_NONE);
67 	customBox->SetLabel(fUseCustom);
68 	fUseCustom->ResizeToPreferred();
69 
70 	fPasswordControl = new BTextControl(bounds, "passwordControl", "Password:",
71 		NULL, B_FOLLOW_NONE);
72 	customBox->AddChild(fPasswordControl);
73 	fPasswordControl->ResizeToPreferred();
74 	fPasswordControl->TextView()->HideTyping(true);
75 	fPasswordControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
76 
77 	bounds.OffsetBy(0.0, fPasswordControl->Bounds().Height() + 5.0);
78 	fConfirmControl = new BTextControl(bounds, "confirmControl",
79 		"Confirm password:", "VeryLongPasswordPossible", B_FOLLOW_NONE);
80 	customBox->AddChild(fConfirmControl);
81 	fConfirmControl->TextView()->HideTyping(true);
82 	fConfirmControl->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
83 
84 	float width, height;
85 	fConfirmControl->GetPreferredSize(&width, &height);
86 	fPasswordControl->ResizeTo(width, height);
87 	fConfirmControl->ResizeTo(width, height);
88 
89 	float divider = be_plain_font->StringWidth("Confirm password:") + 5.0;
90 	fConfirmControl->SetDivider(divider);
91 	fPasswordControl->SetDivider(divider);
92 
93 	customBox->ResizeTo(fConfirmControl->Frame().right + 10.0,
94 		fConfirmControl->Frame().bottom + 10.0);
95 
96 	BButton* button = new BButton(BRect(), "done", "Done", new BMessage(kMsgDone));
97 	topView->AddChild(button);
98 	button->ResizeToPreferred();
99 
100 	BRect frame = customBox->Frame();
101 	button->MoveTo(frame.right - button->Bounds().Width(), frame.bottom + 10.0);
102 
103 	frame = button->Frame();
104 	button->MakeDefault(true);
105 
106 	button = new BButton(frame, "cancel", "Cancel", new BMessage(B_CANCEL));
107 	topView->AddChild(button);
108 	button->ResizeToPreferred();
109 	button->MoveBy(-(button->Bounds().Width() + 10.0), 0.0);
110 
111 	ResizeTo(customBox->Frame().right + 10.0, frame.bottom + 10.0);
112 }
113 
114 
115 void
116 PasswordWindow::Update()
117 {
118 	if (fSettings.IsNetworkPassword())
119 		fUseNetwork->SetValue(B_CONTROL_ON);
120 	else
121 		fUseCustom->SetValue(B_CONTROL_ON);
122 
123 	bool useNetPassword = (fUseCustom->Value() > 0);
124 	fConfirmControl->SetEnabled(useNetPassword);
125 	fPasswordControl->SetEnabled(useNetPassword);
126 }
127 
128 
129 char *
130 PasswordWindow::_SanitizeSalt(const char *password)
131 {
132 	char *salt;
133 
134 	uint8 length = strlen(password);
135 
136 	if (length < 2)
137 		salt = new char[3];
138 	else
139 		salt = new char[length + 1];
140 
141 	uint8 i = 0;
142 	uint8 j = 0;
143 	for (; i < length; i++) {
144 		if (isalnum(password[i]) || password[i] == '.' || password[i] == '/') {
145 			salt[j] = password[i];
146 			j++;
147 		}
148 	}
149 
150 	/*
151 	 *	We need to pad the salt.
152 	 */
153 	while (j < 2) {
154 		salt[j] = '.';
155 		j++;
156 	}
157 
158 	salt[j] = '\0';
159 
160 	return salt;
161 }
162 
163 
164 void
165 PasswordWindow::MessageReceived(BMessage *message)
166 {
167 	switch (message->what) {
168 		case kMsgDone:
169 			fSettings.SetLockMethod(fUseCustom->Value() ? "custom" : "network");
170 			if (fUseCustom->Value()) {
171 				if (strcmp(fPasswordControl->Text(), fConfirmControl->Text())) {
172 					BAlert *alert = new BAlert("noMatch",
173 						"Passwords don't match. Please try again.","OK");
174 					alert->Go();
175 					break;
176 				}
177 				const char *salt = _SanitizeSalt(fPasswordControl->Text());
178 				fSettings.SetPassword(crypt(fPasswordControl->Text(), salt));
179 				delete salt;
180 			} else {
181 				fSettings.SetPassword("");
182 			}
183 			fPasswordControl->SetText("");
184 			fConfirmControl->SetText("");
185 			fSettings.Save();
186 			Hide();
187 			break;
188 
189 	case B_CANCEL:
190 		fPasswordControl->SetText("");
191 		fConfirmControl->SetText("");
192 		Hide();
193 		break;
194 
195 	case kMsgPasswordTypeChanged:
196 		fSettings.SetLockMethod(fUseCustom->Value() > 0 ? "custom" : "network");
197 		Update();
198 		break;
199 
200 	default:
201 		BWindow::MessageReceived(message);
202 		break;
203  	}
204 }
205