View | Details | Raw Unified | Return to bug 42267 | Differences between
and this patch

Collapse All | Expand All

(-)a/management/univention-self-service/build_profile.js (-5 / +6 lines)
 Lines 58-68   var profile = { Link Here 
58
58
59
	layers: {
59
	layers: {
60
		"dojo/dojo": {
60
		"dojo/dojo": {
61
			customBase: true,
61
			customBase: true //,
62
			include: [
62
			//include: [
63
				"ucs/passwordchange",
63
			//	"ucs/PasswordChange",
64
				"ucs/passwordreset"
64
			//	"ucs/PasswordForgotten",
65
			]
65
			//	"ucs/ProtectAccountAccess"
66
			//]
66
		}
67
		}
67
	}
68
	}
68
};
69
};
(-)a/management/univention-self-service/conffiles/usr/share/univention-self-service/www/entries.json (+33 lines)
Line 0    Link Here 
1
@!@
2
import json
3
4
subpages = ['password_change', 'password_forgotten', 'protect_account_access']
5
subpage_variable_path = "umc/self-service/passwordservice/subpage/{}"
6
filtered_subpages = [page for page in subpages if configRegistry.is_true(subpage_variable_path.format(page))]
7
8
9
password_qualities = [
10
	'credit/digits',
11
	'credit/lower',
12
	'credit/upper',
13
	'credit/other',
14
	'forbidden/chars',
15
	'required/chars'
16
]
17
quality_variable_path = "password/quality/{}"
18
filtered_password_qualities = []
19
for quality in password_qualities:
20
	ucr_variable = quality_variable_path.format(quality)
21
	value = configRegistry.get(ucr_variable);
22
	if value:
23
		filtered_password_qualities.append({
24
			'name': quality,
25
			'value': value
26
		})
27
28
29
print json.dumps({
30
	"subpages": filtered_subpages,
31
	"password_quality": filtered_password_qualities
32
})
33
@!@
(-)a/management/univention-self-service/css/document.styl (+64 lines)
 Lines 133-138   div#title > p { Link Here 
133
	color: #619410;
133
	color: #619410;
134
}
134
}
135
135
136
div.PasswordServiceContent {
137
	background: #f3f3f3;
138
	padding: 1.3em;
139
	border-radius: 5px 5px 5px 5px;
140
	-moz-border-radius: 5px 5px 5px 5px;
141
	-webkit-border-radius: 5px 5px 5px 5px;
142
	border: 0px solid #000000;
143
	-webkit-box-shadow: 6px 6px 5px 0px rgba(131,131,131,1);
144
	-moz-box-shadow: 6px 6px 5px 0px rgba(131,131,131,1);
145
	box-shadow: 6px 6px 5px 0px rgba(131,131,131,1);
146
147
	.contentDesc {
148
		font-weight: bold;
149
	}
150
}
151
152
ol.PasswordOl {
153
	margin-left: 0;
154
	padding-right: 0;
155
	padding-left: 0;
156
	list-style-type: none;
157
158
	li.step {
159
		counter-increment: step-counter;
160
		margin-bottom: 1em;
161
162
		div {
163
			margin-top: 0.1em;
164
		}
165
166
		.dijitButton {
167
			margin: 0.6em 0.6em 0 0;
168
		}
169
	}
170
171
	li.step::before {
172
		content: counter(step-counter);
173
		margin-right: 5px;
174
		font-size: 80%;
175
		background-color: rgb(200,200,200);
176
		color: white;
177
		font-weight: bold;
178
		padding: 3px 8px;
179
		border-radius: 3px;
180
	}
181
182
	div.stepLabel {
183
		display: inline;
184
	}
185
}
186
187
ol#PasswordChangeSteps li.step::before {
188
	background-color: #8ebe43;
189
}
190
191
ol#PasswordForgottenSteps li.step::before {
192
	background-color: #fd5745;
193
}
194
195
ol#PasswordProtectSteps li.step::before {
196
	background-color: #f8cd23;
197
}
198
136
div.stepContent {
199
div.stepContent {
137
	margin-top: 1.5em;
200
	margin-top: 1.5em;
138
}
201
}
 Lines 151-156   div.step { Link Here 
151
214
152
div.step.hide-step {
215
div.step.hide-step {
153
	opacity: 0;
216
	opacity: 0;
217
	display: none;
154
	visibility: hidden;
218
	visibility: hidden;
155
	transition: visibility 0s linear 0.5s, opacity 0.5s ease-in-out;
219
	transition: visibility 0s linear 0.5s, opacity 0.5s ease-in-out;
156
}
220
}
(-)a/management/univention-self-service/css/form/Common.styl (-1 / +1 lines)
 Lines 192-198    Link Here 
192
.claro .dijitSelectDisabled,
192
.claro .dijitSelectDisabled,
193
.claro .dijitTextBoxDisabled,
193
.claro .dijitTextBoxDisabled,
194
.claro .dijitTextBoxDisabled .dijitInputInner {
194
.claro .dijitTextBoxDisabled .dijitInputInner {
195
	color: $disabled-text-color;
195
	//color: $disabled-text-color;
196
}
196
}
197
197
198
.dj_webkit .claro .dijitDisabled input {
198
.dj_webkit .claro .dijitDisabled input {
(-)a/management/univention-self-service/css/header.styl (+16 lines)
 Lines 7-12    Link Here 
7
7
8
}
8
}
9
9
10
#header-middle {
11
	position: absolute;
12
	left: 50%;
13
	top: 13px;
14
	width: 20px;
15
	height: 20px;
16
	margin-left: -10px;
17
	background: url("../../univention-management-console/js/dijit/themes/umc/images/icons.svg") -40px -20px no-repeat;
18
}
19
20
#header-middle:hover {
21
	background: url("../../univention-management-console/js/dijit/themes/umc/images/icons.svg") -60px -20px no-repeat;
22
}
23
24
25
10
#header-left {
26
#header-left {
11
	//float:left;
27
	//float:left;
12
	left: 0;
28
	left: 0;
(-)a/management/univention-self-service/css/tabs.styl (-34 / +34 lines)
 Lines 4-53    Link Here 
4
}
4
}
5
5
6
#navigation {
6
#navigation {
7
	.button-container {
7
	.PasswordServiceNav {
8
		display: inline-block;
8
		display: inline-block;
9
		width: 14.2857%;
10
		min-width: 95px;
11
		max-width: 160px;
12
		margin: 5px 0;
13
		position: relative;
14
		vertical-align: top;
15
		cursor: pointer;
9
	}
16
	}
10
17
11
	.button {
18
	.PasswordServiceNav:active {
19
		font-weight: bold;
20
	}
21
22
	.PasswordServiceNavBubble {
23
		-webkit-border-radius: 50%;
24
		-moz-border-radius: 50%;
25
		border-radius: 50%;
26
		background-color: aliceblue;
12
		width: 70px;
27
		width: 70px;
13
		height: 70px;
28
		height: 70px;
14
		margin: 0 2em;
29
		margin: auto;
15
		background: url(icons/tab-buttons.svg) no-repeat;
30
		background-repeat: no-repeat;
16
		display: inline-block;
31
		background-position: 50% 40%;
17
	}
32
	}
18
33
		.password_change {
19
	#register-button {
34
			background-color: #8ebe43;
20
		background-position: 0 -70px;
35
			background-image: url("../../icon/password_change.png");
21
		&.focused {
22
			background-position: 0 0;
23
		}
36
		}
24
	}
37
		.password_forgotten {
25
38
			background-color: #fd5745;
26
	#upload-button {
39
			background-image: url("../../icon/password_forgotten.png");
27
		background-position: -70px -70px;
28
		&.focused {
29
			background-position: -70px 0;
30
		}
40
		}
31
	}
41
		.protect_account_access {
32
42
			background-color: #f8cd23;
33
	#finished-button {
43
			background-image: url("../../icon/protect_account_access.png");
34
		background-position: -140px -70px;
35
		&.focused {
36
			background-position: -140px 0;
37
		}
44
		}
38
	}
39
40
	.loading-bar {
41
		opacity: 0;
42
		transition: opacity 1s ease-in-out;
43
		width: 100%;
44
		height: 32px;
45
		background: url(icons/loading-bubbles.gif) no-repeat;
46
		background-position: center center;
47
	}
48
45
49
	.loading-bar.focused {
46
	.PasswordServiceNavTitle {
50
		opacity: 1;
47
		display: block;
48
		font-size: 1em;
49
		margin-top: 0.5em;
50
		white-space: pre-line;
51
	}
51
	}
52
}
52
}
53
53
(-)a/management/univention-self-service/debian/univention-self-service.install (+1 lines)
 Lines 5-7   univention-self-service-modules usr/sbin/ Link Here 
5
www usr/share/univention-self-service
5
www usr/share/univention-self-service
6
usr/share/univention-self-service/www/
6
usr/share/univention-self-service/www/
7
var/www/univention-self-service
7
var/www/univention-self-service
8
icon/*.png var/www/icon
(-)a/management/univention-self-service/debian/univention-self-service.postinst (-19 / +18 lines)
 Lines 52-78   touch $ACCESS_LOG $ERROR_LOG Link Here 
52
chown self-service:adm $ACCESS_LOG $ERROR_LOG
52
chown self-service:adm $ACCESS_LOG $ERROR_LOG
53
chmod 640 $ACCESS_LOG $ERROR_LOG
53
chmod 640 $ACCESS_LOG $ERROR_LOG
54
54
55
univention-config-registry set \
55
# UCR Variable für Passwort Service
56
	self-service/passwordreset/web/enabled?yes \
56
# default: Passwort Service aktiviert
57
	"ucs/web/overview/entries/service/passwordreset/description=Reset your password or provide contact information" \
57
univention-config-registry set self-service/passwordchange/web/enabled?yes
58
	"ucs/web/overview/entries/service/passwordreset/description/de=Setzen Sie Ihr Passwort zurück oder hinterlegen Sie Kontaktinformationen." \
59
	"ucs/web/overview/entries/service/passwordreset/label=Password Reset" \
60
	"ucs/web/overview/entries/service/passwordreset/label/de=Passwort zurücksetzen" \
61
	"ucs/web/overview/entries/service/passwordreset/link=/univention-self-service/?lang=en-US#passwordreset" \
62
	"ucs/web/overview/entries/service/passwordreset/link/de=/univention-self-service/?lang=de-DE#passwordreset" \
63
	"ucs/web/overview/entries/service/passwordreset/port_http=" \
64
	"ucs/web/overview/entries/service/passwordreset/port_https=443"
65
58
66
univention-config-registry set \
59
# UCR Variablen für Unterseiten des Passwort Services
67
	self-service/passwordchange/web/enabled?yes \
60
univention-config-registry set "umc/self-service/passwordservice/subpage/password_change=yes" \
68
	"ucs/web/overview/entries/service/passwordchange/description=Change your (expired) password." \
61
	"umc/self-service/passwordservice/subpage/password_forgotten=yes" \
69
	"ucs/web/overview/entries/service/passwordchange/description/de=Ändern Sie Ihr (abgelaufenes) Passwort." \
62
	"umc/self-service/passwordservice/subpage/protect_account_access=yes"
70
	"ucs/web/overview/entries/service/passwordchange/label=Change Password" \
63
71
	"ucs/web/overview/entries/service/passwordchange/label/de=Passwort ändern" \
64
# Link für Passwort Service
72
	"ucs/web/overview/entries/service/passwordchange/link=/univention-self-service/?lang=en-US#passwordchange" \
65
# Informationen für den Link zum Passwort Service
73
	"ucs/web/overview/entries/service/passwordchange/link/de=/univention-self-service/?lang=de-DE#passwordchange" \
66
univention-config-registry set "ucs/web/overview/entries/service/passwordchange/label=Password settings" \
67
	"ucs/web/overview/entries/service/passwordchange/label/de=Passwort-Einstellungen" \
68
	"ucs/web/overview/entries/service/passwordchange/description=Password change and protection." \
69
	"ucs/web/overview/entries/service/passwordchange/description/de=Passwort ändern und Kontozugang schützen." \
70
	"ucs/web/overview/entries/service/passwordchange/link=/univention-self-service/?lang=en-US" \
71
	"ucs/web/overview/entries/service/passwordchange/link/de=/univention-self-service/?lang=de-DE" \
74
	"ucs/web/overview/entries/service/passwordchange/port_http=" \
72
	"ucs/web/overview/entries/service/passwordchange/port_http=" \
75
	"ucs/web/overview/entries/service/passwordchange/port_https=443"
73
	"ucs/web/overview/entries/service/passwordchange/port_https=443" \
74
	"ucs/web/overview/entries/service/passwordchange/icon=/icon/password.png"
76
75
77
76
78
if [ "$1" = "configure" ]; then
77
if [ "$1" = "configure" ]; then
(-)a/management/univention-self-service/debian/univention-self-service.postrm (-12 / +10 lines)
 Lines 38-55   case "$1" in Link Here 
38
	;;
38
	;;
39
esac
39
esac
40
40
41
# UCR Variablen bei Deinstallation löschen
41
if [ "$1" = "remove" -o "$1" = "purge" ]; then
42
if [ "$1" = "remove" -o "$1" = "purge" ]; then
42
	univention-config-registry unset \
43
	# Informationen für den Link zum Passwort Service löschen
43
		ucs/web/overview/entries/service/passwordreset/description \
44
		ucs/web/overview/entries/service/passwordreset/description/de \
45
		ucs/web/overview/entries/service/passwordreset/icon \
46
		ucs/web/overview/entries/service/passwordreset/label \
47
		ucs/web/overview/entries/service/passwordreset/label/de \
48
		ucs/web/overview/entries/service/passwordreset/link \
49
		ucs/web/overview/entries/service/passwordreset/link/de \
50
		ucs/web/overview/entries/service/passwordreset/port_http \
51
		ucs/web/overview/entries/service/passwordreset/port_https
52
53
	univention-config-registry unset \
44
	univention-config-registry unset \
54
		ucs/web/overview/entries/service/passwordchange/description \
45
		ucs/web/overview/entries/service/passwordchange/description \
55
		ucs/web/overview/entries/service/passwordchange/description/de \
46
		ucs/web/overview/entries/service/passwordchange/description/de \
 Lines 59-65   if [ "$1" = "remove" -o "$1" = "purge" ]; then Link Here 
59
		ucs/web/overview/entries/service/passwordchange/link \
50
		ucs/web/overview/entries/service/passwordchange/link \
60
		ucs/web/overview/entries/service/passwordchange/link/de \
51
		ucs/web/overview/entries/service/passwordchange/link/de \
61
		ucs/web/overview/entries/service/passwordchange/port_http \
52
		ucs/web/overview/entries/service/passwordchange/port_http \
62
		ucs/web/overview/entries/service/passwordchange/port_https
53
		ucs/web/overview/entries/service/passwordchange/port_https \
54
		ucs/web/overview/entries/service/passwordchange/icon
55
56
	# UCR Variablen für die Unterseiten des Passwort Services löschen
57
	univention-config-registry unset \
58
		umc/self-service/passwordservice/subpage/password_change \
59
		umc/self-service/passwordservice/subpage/password_forgotten \
60
		umc/self-service/passwordservice/subpage/protect_account_access
63
61
64
	# restart, so apache unloads WSGI and deactivats plugin in its config
62
	# restart, so apache unloads WSGI and deactivats plugin in its config
65
	# retry if fail because of to quick successive restarts (from other frontend packages)
63
	# retry if fail because of to quick successive restarts (from other frontend packages)
(-)a/management/univention-self-service/debian/univention-self-service.univention-config-registry (+5 lines)
 Lines 2-4   Type: file Link Here 
2
File: usr/share/univention-self-service/www/languages.json
2
File: usr/share/univention-self-service/www/languages.json
3
Variables: locale
3
Variables: locale
4
Variables: ucs/server/languages/.*
4
Variables: ucs/server/languages/.*
5
6
Type: file
7
File: usr/share/univention-self-service/www/entries.json
8
Variables: umc/self-service/passwordservice/subpage/.*
9
Variables: password/quality/.*
(-)a/management/univention-self-service/debian/univention-self-service.univention-config-registry-variables (+18 lines)
 Lines 15-17   Description[de]=Die Webseite des Password-Self-Service Moduls einschalten (Stand Link Here 
15
Description[en]=Enable the web page of the password self service module (default "yes").
15
Description[en]=Enable the web page of the password self service module (default "yes").
16
Type=bool
16
Type=bool
17
Categories=self-service
17
Categories=self-service
18
19
[umc/self-service/passwordservice/subpage/password_change]
20
Description[de]=Die Unterseite "Passwort ändern" des Password-Self-Service Moduls einschalten (Standard: "yes").
21
Description[en]=Enable the sub page "Password change" of the password self service module (default "yes").
22
Type=bool
23
Categories=self-service
24
25
[umc/self-service/passwordservice/subpage/password_forgotten]
26
Description[de]=Die Unterseite "Passwort vergessen" des Password-Self-Service Moduls einschalten (Standard: "yes").
27
Description[en]=Enable the sub page "Password forgotten" of the password self service module (default "yes").
28
Type=bool
29
Categories=self-service
30
31
[umc/self-service/passwordservice/subpage/protect_account_access]
32
Description[de]=Die Unterseite "Kontozugäng schützen" des Password-Self-Service Moduls einschalten (Standard: "yes").
33
Description[en]=Enable the sub page "Protect account access" of the password self service module (default "yes").
34
Type=bool
35
Categories=self-service
(-)a/management/univention-self-service/js/config.js (-23 / +23 lines)
 Lines 1-43    Link Here 
1
// get locale from query string
1
/**
2
function getQuery(/*String*/ param, /*mixed*/ defaultVal) {
2
* Search the value of the QueryString for an given key.
3
	// parse the URI query string
3
* @param: {string} key - Key for the searched value.
4
	var query = window.location.search.substring(1);
4
* @param: {mixed} defaultVal - default value if no value is found.
5
	var vars = query.split('&');
5
* */
6
	for (var i = 0; i < vars.length; i++) {
6
function getQuery(key, defaultVal) {
7
		// parse the tuple
7
	var queryString = window.location.search.substring(1);
8
		var tuple = vars[i].split('=');
8
	var items = queryString.split('&');
9
		// check whether we found the particular parameter we are interested in
9
	for (var i = 0; i < items.length; i++) {
10
		if (2 == tuple.length && param == tuple[0]) {
10
		var tuple = items[i].split('=');
11
		if (2 == tuple.length && key == tuple[0]) {
11
			return tuple[1];
12
			return tuple[1];
12
		}
13
		}
13
	}
14
	}
15
	return defaultVal;
14
}
16
}
15
17
16
locale = getQuery('lang');
18
17
if (locale) {
19
/**
20
 * Get the current language from the queryString
21
 * */
22
function getLocale() {
23
	var locale = getQuery('lang', 'en-US');
18
	locale = locale.replace('_', '-');
24
	locale = locale.replace('_', '-');
25
	return locale;
19
}
26
}
20
27
21
// load the javascript module that is specified in the hash
22
var selfService = document.location.hash.substr(1);
23
28
24
var dojoConfig = {
29
var dojoConfig = {
25
	isDebug: false,
30
	isDebug: false,
26
	locale: locale,
31
	locale: getLocale(),
27
	async: true,
32
	async: true,
28
	callback: function() {
33
	callback: function() {
29
		require([
34
		require([
30
			"dojo/hash",
35
			"ucs/PasswordService",
31
			"dojo/topic",
32
			"ucs/" + selfService,
33
			"ucs/LanguagesDropDown",
36
			"ucs/LanguagesDropDown",
34
			"dojo/domReady!"
37
			"dojo/domReady!"
35
		], function(hash, topic, app, LanguagesDropDown) {
38
		], function(PasswordService, LanguagesDropDown) {
36
			app.start();
39
			PasswordService.start();
37
			LanguagesDropDown.start();
40
			LanguagesDropDown.start();
38
			topic.subscribe("/dojo/hashchange", function(changedHash) {
39
				window.location.reload();
40
			});
41
		});
41
		});
42
	}
42
	}
43
};
43
};
(-)a/management/univention-self-service/js/ucs/LabelPane.js (-1 / +1 lines)
 Lines 270-276   define([ Link Here 
270
			if (description && !this.content.handlesTooltips) {
270
			if (description && !this.content.handlesTooltips) {
271
				//default to the 'new' tooltip style
271
				//default to the 'new' tooltip style
272
				if (!this.usesHoverTooltip) {
272
				if (!this.usesHoverTooltip) {
273
					if (this._isLabelDisplayed() && this.label && !(this.label === '&nbsp;')) {
273
					if (this._isLabelDisplayed() && this.label && this.label !== '&nbsp;') {
274
						labelNode = this._getLabelNode();
274
						labelNode = this._getLabelNode();
275
						this.tooltipNode = domConstruct.create("div",{
275
						this.tooltipNode = domConstruct.create("div",{
276
							'class': "umcDescription umcDescriptionIcon"
276
							'class': "umcDescription umcDescriptionIcon"
(-)a/management/univention-self-service/js/ucs/PasswordBox.js (+161 lines)
Line 0    Link Here 
1
/*
2
 * Copyright 2011-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
/*global define*/
30
31
define([
32
	"dojo/_base/declare",
33
	"dojo/_base/lang",
34
	"dojo/_base/array",
35
	"dojo/when",
36
	"dojo/json",
37
	"dijit/form/ValidationTextBox",
38
	"./_FormWidgetMixin",
39
	"./LabelPane",
40
	"./lib",
41
	"./i18n!."
42
], function(declare, lang, array, when, json, ValidationTextBox, _FormWidgetMixin, LabelPane, lib, _) {
43
	return declare('umc.widgets.PasswordBox', [ ValidationTextBox, _FormWidgetMixin ], {
44
		label: null,
45
		type: 'password',
46
		required: true,
47
		missingMessage: _('This value is required.'),
48
		promptMessage: '',
49
		invalidMessage: '',
50
		tooltipPosition: ['below', 'after'],
51
		active_password_qualities: null,
52
		password_qualities: {
53
			'credit/digits': {
54
				reg: '.{%[0]}',
55
				promptMessage: _('Required length:')
56
			},
57
			'credit/lower': {
58
				reg: '^(.*?[a-z]){%[0],}',
59
				promptMessage: _('Required number of lower case letters:')
60
			},
61
			'credit/upper': {
62
				reg: '^(.*?[A-Z]){%[0],}',
63
				promptMessage: _('Required number of upper case letters:')
64
			},
65
			'credit/other': {
66
				reg: '^(.*?[^a-zA-Z0-9]){%[0],}',
67
				promptMessage: _('Required number of special characters (nor digit or letters):')
68
			},
69
			'forbidden/chars': {
70
				reg: "^((?![%[0]]).)*$",
71
				promptMessage: _('Forbidden chars:')
72
			},
73
			'required/chars': {
74
				reg: '[%[0]]',
75
				promptMessage: _('Required chars:')
76
			}
77
		},
78
79
		buildRendering: function() {
80
			this.inherited(arguments);
81
			if (this.label !== undefined) {
82
				this._createLabelNode();
83
			}
84
			when(lib.getBackendInformation()).then(lang.hitch(this, function(data) {
85
				var result = JSON.parse(data, true);
86
				this.active_password_qualities = result.password_quality;
87
				this.setPromptMessage(result.password_quality);
88
			}));
89
		},
90
91
		isValid: function() {
92
			return this.validator();
93
		},
94
95
		_hasValue: function(password) {
96
			if (password) {
97
				return true;
98
			} else {
99
				this.setPromptMessage();
100
				this.invalidMessage = _('This value is required.');
101
				return false;
102
			}
103
		},
104
105
		/** Checks if the password meets the active password qualities.
106
		 * @param {string} password - Current value of the input box.
107
		 * **/
108
		_hasValidPasswordQuality: function(password) {
109
			var result = array.filter(this.active_password_qualities, lang.hitch(this, function(iqual) {
110
				var quality = this.password_qualities[iqual.name];
111
				var reg_str = lang.replace(quality.reg, [iqual.value], /\%\[([^\]]+)\]/g);
112
				var reg = new RegExp(reg_str);
113
				if (reg.test(password)) {
114
					return true;
115
				} else {
116
					this.invalidMessage += lang.replace('{0} {1}{2}', [quality.promptMessage, iqual.value, '</br>']);
117
					this.promptMessage = this.invalidMessage;
118
					return false;
119
				}
120
			}));
121
			if (result.length === this.active_password_qualities.length) {
122
				this.setValid(true);
123
				return true;
124
			} else {
125
				return false;
126
			}
127
		},
128
129
		validator: function() {
130
			this.invalidMessage = '';
131
			this.promptMessage = '';
132
			var password = this.get('value');
133
			return this._hasValue(password) && this._hasValidPasswordQuality(password);
134
		},
135
136
		setPromptMessage: function(active_qualities) {
137
			var qualities = active_qualities || this.active_password_qualities;
138
			if (qualities && qualities.length) {
139
				this.promptMessage = _('The password must fullfill following conditions:');
140
				array.forEach(qualities, lang.hitch(this, function(iqual) {
141
					var quality = this.password_qualities[iqual.name];
142
					this.promptMessage += lang.replace('{0}{1} {2}', ['</br>', quality.promptMessage, iqual.value]);
143
				}));
144
			}
145
		},
146
147
		_createLabelNode: function() {
148
			this.label = new LabelPane({
149
				content: this,
150
				'class': this['class']
151
			});
152
			this.set('class', '');
153
		},
154
155
		reset: function() {
156
			this.set('value', '');
157
			this.set('disabled', false);
158
			this.setValid();
159
		}
160
	});
161
});
(-)a/management/univention-self-service/js/ucs/PasswordChange.js (+246 lines)
Line 0    Link Here 
1
/*
2
 * Copyright 2015-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
/*global define require console window */
30
31
define([
32
	"dojo/_base/lang",
33
	"dojo/on",
34
	"dojo/keys",
35
	"dojo/dom",
36
	"dojo/json",
37
	"dojo/request/xhr",
38
	"dijit/form/Button",
39
	"put-selector/put",
40
	"./TextBox",
41
	"./PasswordBox",
42
	"./lib",
43
	"./i18n!."
44
], function(lang, on, keys, dom, json, xhr, Button, put, TextBox, PasswordBox, lib, _) {
45
46
	return {
47
		title: _('Password change'),
48
		desc: _('Change your (expired) password.'),
49
		hash: 'passwordchange',
50
		contentContainer: null,
51
		steps: null,
52
53
		/**
54
		 * Returns the title of the subpage.
55
		 * */
56
		getTitle: function() {
57
			return _(this.title);
58
		},
59
60
		/**
61
		 * Returns the description of the subpage.
62
		 * */
63
		getDesc: function() {
64
			return _(this.desc);
65
		},
66
67
		/**
68
		 * Return the content node of the subpage.
69
		 * If the content does not exists, it will be generated.
70
		 * */
71
		getContent: function() {
72
			if (!this.contentContainer) {
73
				this.contentContainer = put('div.contentWrapper');
74
				put(this.contentContainer, 'div.contentDesc', this.getDesc());
75
				put(this.contentContainer, this._getSteps());
76
			}
77
			return this.contentContainer;
78
		},
79
80
		/**
81
		 * Return the steps for the content node.
82
		 * If the steps do not exists, they will be generated.
83
		 * Note: Please call getContent for generating the steps.
84
		 * */
85
		_getSteps: function() {
86
			if (!this.steps) {
87
				this.steps = put('ol#PasswordChangeSteps.PasswordOl');
88
				this._createUsername();
89
				this._createOldPassword();
90
				this._createNewPassword();
91
				this._createSubmit();
92
			}
93
			return this.steps;
94
		},
95
96
		/**
97
		 * Creates input field for username.
98
		 * */
99
		_createUsername: function() {
100
			var step = put('li.step');
101
			var label = put('div.stepLabel', _('Username'));
102
			put(step, label);
103
			this._username = new TextBox({
104
				'class': 'soloLabelPane',
105
				isValid: function() {
106
					return !!this.get('value');
107
				},
108
				required: true
109
			});
110
			this._username.startup();
111
			put(step, this._username.domNode);
112
			put(this.steps, step);
113
		},
114
115
		/**
116
		 * Creates input field for old password.
117
		 * */
118
		_createOldPassword: function() {
119
			var step = put('li.step');
120
			var label = put('div.stepLabel', _('Old Password'));
121
			put(step, label);
122
			this._oldPassword = new TextBox({
123
				'class': 'soloLabelPane',
124
				type: 'password',
125
				isValid: function() {
126
					return !!this.get('value');
127
				},
128
				required: true
129
			});
130
			this._oldPassword.startup();
131
			put(step, this._oldPassword.domNode);
132
			put(this.steps, step);
133
		},
134
135
		/**
136
		 * Creates input fields for new password.
137
		 * */
138
		_createNewPassword: function() {
139
			var step = put('li.step');
140
			var label = put('div.stepLabel', _('New Password'));
141
			put(step, label);
142
			this._newPassword = new PasswordBox({
143
				'class': 'soloLabelPane left'
144
			});
145
			this._newPassword.startup();
146
			put(step, this._newPassword.domNode);
147
			put(this.steps, step);
148
149
			step = put('li.step');
150
			label = put('div.stepLabel', _('New Password (retype)'));
151
			put(step, label);
152
			this._verifyPassword = new TextBox({
153
				type: 'password',
154
				'class': 'soloLabelPane',
155
				isValid: lang.hitch(this, function() {
156
					return this._newPassword.get('value') ===
157
						this._verifyPassword.get('value');
158
				}),
159
				invalidMessage: _('The passwords do not match, please retype again.'),
160
				required: true
161
			});
162
			this._verifyPassword.startup();
163
			put(step, this._verifyPassword.domNode);
164
			put(this.steps, step);
165
		},
166
167
		/**
168
		 * Creates submit button.
169
		 * */
170
		_createSubmit: function() {
171
			var step = put('div');
172
			this._submitButton = new Button({
173
				label: _('Change password'),
174
				onClick: lang.hitch(this, '_setPassword')
175
			});
176
			put(step, '>', this._submitButton.domNode);
177
178
			// let the user submit the form by pressing ENTER
179
			on(document, "keyup", lang.hitch(this, function(evt) {
180
				if (evt.keyCode === keys.ENTER && !this._submitButton.get('disabled')) {
181
					this._setPassword();
182
				}
183
			}));
184
			put(this.steps, step);
185
		},
186
187
		/**
188
		 * Changes the current password if all input fields are valid.
189
		 * */
190
		_setPassword: function() {
191
			this._submitButton.set('disabled', true);
192
			var allInputFieldsAreValid = this._username.isValid() &&
193
				this._oldPassword.isValid() &&
194
				this._newPassword.isValid() &&
195
				this._verifyPassword.isValid();
196
197
			if (allInputFieldsAreValid) {
198
				data = json.stringify({
199
					password: {
200
						'username': this._username.get('value'),
201
						'password': this._oldPassword.get('value'),
202
						'new_password': this._newPassword.get('value')
203
					}
204
				});
205
206
				xhr.post('/univention-management-console/set', {
207
					handleAs: 'json',
208
					headers: {
209
						'Content-Type': 'application/json',
210
						'Accept-Language': lib.getQuery('lang') || 'en-US'
211
					},
212
					data: data
213
				}).then(lang.hitch(this, function(data) {
214
					lib.showLastMessage({
215
						content: data.message,
216
						'class': '.success'
217
					});
218
					this._clearAllInputFields();
219
				}), lang.hitch(this, function(err) {
220
					var message = err.name + ": " + err.message;
221
					if (err.response && err.response.data && err.response.data.message) {
222
						message = err.response.data.message;
223
					}
224
					lib.showMessage({
225
						content: message,
226
						'class': '.error'
227
					});
228
				})).always(lang.hitch(this, function(){
229
					this._submitButton.set('disabled', false);
230
				}));
231
			} else {
232
				this._submitButton.set('disabled', false);
233
			}
234
		},
235
236
		/**
237
		 * Clears all input field values of the subpage.
238
		 * */
239
		_clearAllInputFields: function() {
240
			this._username.reset();
241
			this._oldPassword.reset();
242
			this._newPassword.reset();
243
			this._verifyPassword.reset();
244
		}
245
	};
246
});
(-)a/management/univention-self-service/js/ucs/PasswordForgotten.js (+449 lines)
Line 0    Link Here 
1
/*
2
 * Copyright 2015-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
/*global define require console window */
30
31
define([
32
	"dojo/_base/lang",
33
	"dojo/_base/array",
34
	"dojo/on",
35
	"dojo/keys",
36
	"dojo/dom",
37
	"dojo/json",
38
	"dojo/request/xhr",
39
	"dijit/form/Button",
40
	"put-selector/put",
41
	"./ContainerWidget",
42
	"./LabelPane",
43
	"./TextBox",
44
	"./PasswordBox",
45
	"./RadioButton",
46
	"./lib",
47
	"./i18n!."
48
], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, LabelPane, TextBox, PasswordBox, RadioButton, lib, _) {
49
50
	return {
51
		title: _("Password forgotten"),
52
		desc: _("Forgot your password? Set a new one: "),
53
		altDesc: _("Set a new password!"),
54
		hash: 'passwordreset',
55
		contentContainer: null,
56
		steps: null,
57
		selectedRenewOption: null,
58
59
		/**
60
		 * Returns the title of the subpage.
61
		 * */
62
		getTitle: function() {
63
			return _(this.title);
64
		},
65
66
		/**
67
		 * Returns the description for the subpage:
68
		 * Request New Password.
69
		 * */
70
		getRequestNewPassDesc: function() {
71
			return _(this.desc);
72
		},
73
74
		/**
75
		 * Returns the description for the subpage:
76
		 * Set New Password.
77
		 * */
78
		getSetNewPassDesc: function() {
79
			return _(this.altDesc);
80
		},
81
82
		/**
83
		 * Checks if the the query string contains credentials
84
		 * for setting a new password.
85
		 * True -Return a subpage to set a new password.
86
		 * False - Return a subpage to request a new password.
87
		 * */
88
		getContent: function() {
89
			this.contentContainer = put('div.contentWrapper');
90
			var credentials = this._getCredentials();
91
			if (credentials) {
92
				put(this.contentContainer, 'div.contentDesc', this.getSetNewPassDesc());
93
				put(this.contentContainer, this._getSetNewSteps());
94
			} else {
95
				put(this.contentContainer, 'div.contentDesc', this.getRequestNewPassDesc());
96
				put(this.contentContainer, this._getRequestSteps());
97
			}
98
			return this.contentContainer;
99
		},
100
101
		/**
102
		 * Return the steps for the subpage:
103
		 * Request New Password.
104
		 * If the steps do not exists, they will be generated.
105
		 * Note: Please call getContent for generating the steps.
106
		 * */
107
		_getRequestSteps: function() {
108
			if (!this.steps) {
109
				this.steps = put('ol#PasswordForgottenSteps.PasswordOl');
110
				this._createUsername();
111
			}
112
			return this.steps;
113
		},
114
115
		/**
116
		 * Return the steps for the subpage:
117
		 * Set New Password.
118
		 * If the steps do not exists, they will be generated.
119
		 * Note: Please call getContent for generating the steps.
120
		 * */
121
		_getSetNewSteps: function() {
122
			if (!this.steps) {
123
				this.steps = put('ol#PasswordForgottenSteps.PasswordOl');
124
				this._createNewPassword();
125
				this._createSubmitNewPassword();
126
			}
127
			return this.steps;
128
		},
129
130
		/**
131
		 * Creates input field for username and submit button.
132
		 * */
133
		_createUsername: function() {
134
			var step = put('li.step');
135
			var label = put('div.stepLabel', _('Username'));
136
			put(step, label);
137
			this._username = new TextBox({
138
				'class': 'soloLabelPane',
139
				isValid: function() {
140
					return !!this.get('value');
141
				},
142
				required: true
143
			});
144
			this._username.on('keyup', lang.hitch(this, function(evt) {
145
				if (evt.keyCode === keys.ENTER) {
146
					this._getResetMethods();
147
				}
148
			}));
149
			this._username.startup();
150
			put(step, this._username.domNode);
151
152
			this._usernameButton = new Button({
153
				label: _('Next'),
154
				onClick: lang.hitch(this, '_getResetMethods')
155
			});
156
			put(step, this._usernameButton.domNode);
157
			put(this.steps, step);
158
		},
159
160
		/**
161
		 * Gets the available renew options for the user from
162
		 * the server.
163
		 * */
164
		_getResetMethods: function() {
165
			this._username.set('disabled', true);
166
			this._usernameButton.set('disabled', true);
167
168
			if (this._username.isValid()) {
169
				data = json.stringify({
170
					'username': this._username.get('value')
171
				});
172
				xhr.post('passwordreset/get_reset_methods', {
173
					handleAs: 'json',
174
					headers: {
175
						'Content-Type': 'application/json',
176
						'Accept-Language': lib.getQuery('lang') || 'en-US'
177
					},
178
					data: data
179
				}).then(lang.hitch(this, function(data) {
180
					lib._removeMessage();
181
					put(this._usernameButton.domNode, '.dijitHidden');
182
					this._createRenewOptions(data.result);
183
				}), lang.hitch(this, function(err){
184
					var message = err.name + ": " + err.message;
185
					if (err.response && err.response.data && err.response.data.message) {
186
						message = err.response.data.message;
187
					}
188
					lib.showMessage({
189
						content: message,
190
						'class': '.error'
191
					});
192
					this._usernameButton.set('disabled', false);
193
					this._username.set('disabled', false);
194
				}));
195
			} else {
196
				this._usernameButton.set('disabled', false);
197
				this._username.set('disabled', false);
198
			}
199
		},
200
201
		/**
202
		 * Creates a list of all options which are
203
		 * available to request a new password.
204
		 * @param {array} options - List of password renew options.
205
		 * */
206
		_createRenewOptions: function(options) {
207
			// TODO: skipable for having a pin
208
			var step = put('li.step.hide-step');
209
			var label = put('div.stepLabel', _('Please choose an option to renew your password.'));
210
			put(step, label);
211
			var renewOptions = this._renderRenewOptions(options);
212
			put(label, renewOptions);
213
			this._requestTokenButton = new Button({
214
				label: _('Next'),
215
				onClick: lang.hitch(this, '_requestToken')
216
			});
217
			put(step, this._requestTokenButton.domNode);
218
			put(this.steps, step);
219
		},
220
221
		/**
222
		 * Renders a pair of label and radioButton for each
223
		 * renew option.
224
		 * */
225
		_renderRenewOptions: function(options) {
226
			this._tokenOptions = new ContainerWidget({});
227
			array.forEach(options, lang.hitch(this, function(obj, idx){
228
				var radioButton = new RadioButton({
229
					name: 'button' + idx,
230
					label: obj.label,
231
					method: obj.id,
232
					checked: idx === 0,
233
					radioButtonGroup: 'token',
234
					_categoryID: 'token'
235
				});
236
				var label = new LabelPane({
237
					'class': 'ucsRadioButtonLabel',
238
					content: radioButton
239
				});
240
				this._tokenOptions.addChild(label);
241
			}));
242
			return this._tokenOptions.domNode;
243
		},
244
245
		/**
246
		 * Requests a mail or pin from the server to renew the
247
		 * password.
248
		 * */
249
		_requestToken: function() {
250
			//TODO: Display the renew option for mobilenumber
251
			//TODO: Add an option to request a new mail/sms
252
			if (this._getRenewOption()) {
253
				this._requestTokenButton.set('disabled', true);
254
				data = json.stringify({
255
					'username': this._username.get('value'),
256
					'method': this.selectedRenewOption.method
257
				});
258
				xhr.post('passwordreset/send_token', {
259
					handleAs: 'json',
260
					headers: {
261
						'Content-Type': 'application/json',
262
						'Accept-Language': lib.getQuery('lang') || 'en-US'
263
					},
264
					data: data
265
				}).then(lang.hitch(this, function(data) {
266
					this._showNewPasswordHowTo();
267
					lib.showMessage({
268
						content: data.message,
269
						'class': '.success'
270
					});
271
					put(this._requestTokenButton.domNode, '.dijitHidden');
272
				}), lang.hitch(this, function(err){
273
					var message = err.name + ": " + err.message;
274
					if (err.response && err.response.data && err.response.data.message) {
275
						message = err.response.data.message;
276
					}
277
					lib.showMessage({
278
						content: message,
279
						targetNode: this.tokenNode,
280
						'class': '.error'
281
					});
282
					this._requestTokenButton.set('disabled', false);
283
				}));
284
			}
285
		},
286
287
		/**
288
		 * Gets the selected renew option.
289
		 * */
290
		_getRenewOption: function() {
291
			array.some(this._tokenOptions.getChildren(), lang.hitch(this, function(option) {
292
				var radioButton = option.getChildren()[0];
293
				if (radioButton.checked) {
294
					this.selectedRenewOption= {
295
						label: radioButton.get('label'),
296
						method: radioButton.get('method')
297
					};
298
				}
299
			}));
300
			return this.selectedRenewOption;
301
		},
302
303
		/**
304
		 * Creates a message with instructions about what
305
		 * todo next to renew the password.
306
		 * */
307
		_showNewPasswordHowTo: function() {
308
			// TODO: add option for sms
309
			var step = put('li.step');
310
			var label = put('div.stepLabel', _('You have mail!'));
311
			put(step, label);
312
			var msg = put('div.soloLabelPane', _('We have send you an e-mail to your alternative e-mail address, that you have provided on the page "Protect Account Access". Please check your mails and follow the link to renew your password.'));
313
			put(step, msg);
314
			var hint = put('div.soloLabelPane', _('If you did not received an e-mail please check your spam directory or use this link to go back to step 2.'));
315
			put(step, hint);
316
			put(this.steps, step);
317
		},
318
319
		/**
320
		 * Creates input fields to set a new password.
321
		 */
322
		_createNewPassword: function() {
323
			var step = put('li.step');
324
			var label = put('div.stepLabel', _('New Password'));
325
			put(step, label);
326
			this._newPassword = new PasswordBox({
327
				'class': 'soloLabelPane'
328
			});
329
			this._newPassword.on('keyup', lang.hitch(this, function(evt) {
330
				if (evt.keyCode === keys.ENTER) {
331
					this._setPassword();
332
				}
333
			}));
334
			this._newPassword.startup();
335
			put(step, this._newPassword.domNode);
336
			put(this.steps, step);
337
338
			step = put('li.step');
339
			label = put('div.stepLabel', _('New Password (retype)'));
340
			put(step, label);
341
			this._verifyPassword = new TextBox({
342
				type: 'password',
343
				'class': 'soloLabelPane',
344
				isValid: lang.hitch(this, function() {
345
					return this._newPassword.get('value') ===
346
						this._verifyPassword.get('value');
347
				}),
348
				invalidMessage: _('The passwords do not match, please retype again.'),
349
				required: true
350
			});
351
			this._verifyPassword.on('keyup', lang.hitch(this, function(evt) {
352
				if (evt.keyCode === keys.ENTER) {
353
					this._setPassword();
354
				}
355
			}));
356
			this._verifyPassword.startup();
357
			put(step, this._verifyPassword.domNode);
358
			put(this.steps, step);
359
		},
360
361
		/**
362
		 * Creates submit button.
363
		 * */
364
		_createSubmitNewPassword: function() {
365
			var step = put('div');
366
			this._setPasswordButton = new Button({
367
				label: _('Change password'),
368
				onClick: lang.hitch(this, '_setPassword')
369
			});
370
			put(step, this._setPasswordButton.domNode);
371
			put(this.steps, step);
372
		},
373
374
		/**
375
		 * Sets the new password by sending it to the server.
376
		 */
377
		_setPassword: function() {
378
			this._disableNewPasswordInputs(true);
379
			var credentials = this._getCredentials();
380
381
			var isTokenAndNewPassValid = credentials &&
382
				this._newPassword.isValid() &&
383
				this._verifyPassword.isValid();
384
385
			if (isTokenAndNewPassValid) {
386
				data = json.stringify({
387
					'username': credentials.username,
388
					'password': this._verifyPassword.get('value'),
389
					'token' : credentials.token
390
				});
391
				xhr.post('passwordreset/set_password', {
392
					handleAs: 'json',
393
					headers: {
394
						'Content-Type': 'application/json',
395
						'Accept-Language': lib.getQuery('lang') || 'en-US'
396
					},
397
					data: data
398
				}).then(lang.hitch(this, function(data) {
399
					lib.showLastMessage({
400
						content: data.message,
401
						'class': '.success'
402
					});
403
					this._resetNewPasswordInputs();
404
				}), lang.hitch(this, function(err){
405
					var message = err.name + ": " + err.message;
406
					if (err.response && err.response.data && err.response.data.message) {
407
						message = err.response.data.message;
408
					}
409
					lib.showMessage({
410
						content: message,
411
						targetNode: this.newPasswordNode,
412
						'class': '.error'
413
					});
414
					this._disableNewPasswordInputs(false);
415
				}));
416
			} else {
417
				this._disableNewPasswordInputs(false);
418
			}
419
		},
420
421
		_disableNewPasswordInputs: function(/* boolean */ isDiabled) {
422
			this._setPasswordButton.set('disabled', isDiabled);
423
			this._newPassword.set('disabled', isDiabled);
424
			this._verifyPassword.set('disabled', isDiabled);
425
		},
426
427
		_resetNewPasswordInputs: function() {
428
			this._setPasswordButton.set('value', '');
429
			this._newPassword.set('value', '');
430
			this._verifyPassword.set('value', '');
431
			this._disableNewPasswordInputs(false);
432
		},
433
434
		/**
435
		 * Gets credentials (token and username) from query string.
436
		 * */
437
		_getCredentials: function() {
438
			var token = lib.getQuery('token');
439
			var username = lib.getQuery('username');
440
			if (token && username) {
441
				return {
442
					username: username,
443
					token: token
444
				};
445
			}
446
			return null;
447
		}
448
	};
449
});
(-)a/management/univention-self-service/js/ucs/PasswordService.js (+143 lines)
Line 0    Link Here 
1
/*
2
 * Copyright 2015-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
30
define([
31
	"dojo/hash",
32
	"dojo/topic",
33
	"dojo/_base/lang",
34
	"dojo/_base/array",
35
	"dojo/_base/xhr",
36
	"dojo/json",
37
	"put-selector/put",
38
	"dojo/dom",
39
	"dijit/layout/StackContainer",
40
	"dijit/layout/ContentPane",
41
	"./PasswordChange",
42
	"./PasswordForgotten",
43
	"./ProtectAccountAccess",
44
	"./lib",
45
	"dojo/domReady!"
46
], function(hash, topic, lang, array, xhr, JSON, put, dom, StackContainer, ContentPane, PasswordChange, PasswordForgotten, ProtectAccountAccess, lib){
47
48
	return {
49
		content_container: null,
50
		content_controller: null,
51
		backend_info: null,
52
		subpages: {
53
			"password_change": PasswordChange,
54
			"password_forgotten": PasswordForgotten,
55
			"protect_account_access": ProtectAccountAccess
56
		},
57
		site_hashes: {},
58
59
		/**
60
		 * Builds the active subpages of the
61
		 * Password Service.
62
		 */
63
		start: function() {
64
			this._initContainer();
65
			this._initController();
66
			this._subscribeOnHashEvents();
67
			this._requestActiveSubpages();
68
		},
69
70
		_subscribeOnHashEvents: function() {
71
			topic.subscribe("/dojo/hashchange", lang.hitch(this, function(changedHash) {
72
				//window.location.reload();
73
				lib._removeMessage();
74
				this._loadSubpage(changedHash);
75
			}));
76
		},
77
78
		/**
79
		 * Requests the active subpages.
80
		 **/
81
		_requestActiveSubpages: function() {
82
			xhr.get({
83
				url: "/univention-self-service/entries.json",
84
				load: lang.hitch(this, function(data) {
85
					this.backend_info = JSON.parse(data, true);
86
					this._addSubPages(this.backend_info.subpages || []);
87
				}),
88
				error: lang.hitch(this, function(data) {
89
					console.error(data);
90
				})
91
			});
92
		},
93
94
		_initContainer : function() {
95
			this.content_container = new StackContainer({
96
				"class" : "PasswordServiceContent",
97
				id: "contentContainer",
98
				doLayout: false
99
			}, "content");
100
			this.content_container.startup();
101
		},
102
103
		_initController: function() {
104
			var navContainer = dom.byId('navigation');
105
			this.content_controller = put(navContainer, ".PasswordServiceController");
106
		},
107
108
		/**
109
		 * Adds the subpages by name to the Password Service.
110
		 * */
111
		_addSubPages: function(page_list) {
112
			array.forEach(page_list, lang.hitch(this, function(page_name){
113
				var module = this.subpages[page_name];
114
				if (module) {
115
					var subpage = new ContentPane({
116
						content: module.getContent()
117
					});
118
					this.site_hashes[module.hash] = subpage;
119
					var nav = put("div.PasswordServiceNav", {
120
						onclick: lang.hitch(this, function() {
121
							hash(module.hash);
122
						})
123
					});
124
					var bubble = put(nav, "div.PasswordServiceNavBubble" + "." + page_name);
125
					var title = put(nav, "div.PasswordServiceNavTitle", {
126
						innerHTML: module.getTitle()
127
					});
128
					put(this.content_controller, nav);
129
					this.content_container.addChild(subpage);
130
				}
131
			}));
132
			this._loadSubpage(hash());
133
		},
134
135
		_loadSubpage: function(changedHash) {
136
			var subpage = this.site_hashes[changedHash];
137
			if (!subpage) {
138
				subpage = this.content_container.getChildren()[0];
139
			}
140
			this.content_container.selectChild(subpage);
141
		}
142
    };
143
});
(-)a/management/univention-self-service/js/ucs/ProtectAccountAccess.js (+345 lines)
Line 0    Link Here 
1
/*
2
 * Copyright 2015-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
/*global define require console window */
30
31
define([
32
	"dojo/_base/lang",
33
	"dojo/_base/array",
34
	"dojo/on",
35
	"dojo/keys",
36
	"dojo/dom",
37
	"dojo/json",
38
	"dojo/request/xhr",
39
	"dijit/form/Button",
40
	"put-selector/put",
41
	"./ContainerWidget",
42
	"./TextBox",
43
	"./RadioButton",
44
	"./lib",
45
	"./i18n!."
46
], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, TextBox, RadioButton, lib, _) {
47
48
	return {
49
		title: _('Protect Account Access'),
50
		desc: _('Everyone forgets their password now and then. Protect yourself and activate the opportunity to set a new password.'),
51
		hash: 'setcontactinformation',
52
		contentContainer: null,
53
		steps: null,
54
55
		/**
56
		 * Returns the title of the subpage.
57
		 * */
58
		getTitle: function() {
59
			return _(this.title);
60
		},
61
62
		/**
63
		 * Returns the description of the subpage.
64
		 * */
65
		getDesc: function() {
66
			return _(this.desc);
67
		},
68
69
		/**
70
		 * Return the content node of the subpage.
71
		 * If the content does not exists, it will be generated.
72
		 * */
73
		getContent: function() {
74
			if (!this.contentContainer) {
75
				this.contentContainer = put('div.contentWrapper');
76
				put(this.contentContainer, 'div.contentDesc', this.getDesc());
77
				put(this.contentContainer, this._getSteps());
78
			}
79
			return this.contentContainer;
80
		},
81
82
		/**
83
		 * Return the steps for the content node.
84
		 * If the steps do not exists, they will be generated.
85
		 * Note: Please call getContent for generating the steps.
86
		 * */
87
		_getSteps: function() {
88
			if (!this.steps) {
89
				this.steps = put('ol#PasswordProtectSteps.PasswordOl');
90
				this._createUsername();
91
				this._createPassword();
92
				this._createSubmit();
93
			}
94
			return this.steps;
95
		},
96
97
		/**
98
		 * Creates input field for username.
99
		 * */
100
		_createUsername: function() {
101
			var step = put('li.step');
102
			var label = put('div.stepLabel', _('Username'));
103
			put(step, label);
104
			this._username = new TextBox({
105
				'class': 'soloLabelPane',
106
				isValid: function() {
107
					return !!this.get('value');
108
				},
109
				required: true
110
			});
111
			this._username.on('keyup', lang.hitch(this, function(evt) {
112
				if (evt.keyCode === keys.ENTER) {
113
					this._getContactInformation();
114
				}
115
			}));
116
			this._username.startup();
117
			put(step, this._username.domNode);
118
			put(this.steps, step);
119
		},
120
121
		/**
122
		 * Creates input field for password.
123
		 * */
124
		_createPassword: function() {
125
			var step = put('li.step');
126
			var label = put('div.stepLabel', _('Password'));
127
			put(step, label);
128
			this._password = new TextBox({
129
				'class': 'soloLabelPane',
130
				isValid: function() {
131
					return !!this.get('value');
132
				},
133
				required: true,
134
				type: 'password'
135
			});
136
			this._password.on('keyup', lang.hitch(this, function(evt) {
137
				if (evt.keyCode === keys.ENTER) {
138
					this._getContactInformation();
139
				}
140
			}));
141
			this._password.startup();
142
			put(step, this._password.domNode);
143
			put(this.steps, step);
144
		},
145
146
		/**
147
		 * Creates submit button.
148
		 * */
149
		_createSubmit: function() {
150
			var step = put('div');
151
			this._showContactInformationButton = new Button({
152
				label: _('Next'),
153
				onClick: lang.hitch(this, '_getContactInformation')
154
			});
155
			put(step, this._showContactInformationButton.domNode);
156
			put(this.steps, step);
157
		},
158
159
		/**
160
		 * Requests available renew options.
161
		 * */
162
		_getContactInformation: function() {
163
			this._username.set('disabled', true);
164
			this._password.set('disabled', true);
165
			this._showContactInformationButton.set('disabled', true);
166
167
			var validCredentials = this._username.isValid() && this._password.isValid();
168
			if (validCredentials) {
169
				data = json.stringify({
170
					'username': this._username.get('value'),
171
					'password': this._password.get('value')
172
				});
173
				xhr.post('passwordreset/get_contact', {
174
					handleAs: 'json',
175
					headers: {
176
						'Content-Type': 'application/json',
177
						'Accept-Language': lib.getQuery('lang') || 'en-US'
178
					},
179
					data: data
180
				}).then(lang.hitch(this, function(data) {
181
					lib._removeMessage();
182
					put(this._showContactInformationButton.domNode, '.dijitHidden');
183
					this._createRenewOptions(data.result);
184
				}), lang.hitch(this, function(err){
185
					var message = err.name + ": " + err.message;
186
					if (err.response && err.response.data && err.response.data.message) {
187
						message = err.response.data.message;
188
					}
189
					lib.showMessage({
190
						content: message,
191
						'class': '.error'
192
					});
193
					this._showContactInformationButton.set('disabled', false);
194
					this._username.set('disabled', false);
195
					this._password.set('disabled', false);
196
				}));
197
			} else {
198
				this._showContactInformationButton.set('disabled', false);
199
				this._username.set('disabled', false);
200
				this._password.set('disabled', false);
201
			}
202
		},
203
204
		/**
205
		 * Creates renew options.
206
		 * @param {array} renewOptions - List of renew options.
207
		 * */
208
		_createRenewOptions: function(renewOptions) {
209
			var options = renewOptions.length ? renewOptions : [{id: "email", value: '', label: "E-Mail"}];
210
			var step = put('li.step');
211
			this._renewOptions = step;
212
			var label = put('div.stepLabel', _('Activate renew options.'));
213
			put(step, label);
214
			this._renewInputs = array.map(options, function(option) {
215
				var optionNode = put('div');
216
				put(optionNode, 'div', option.label + _(' (retype)'));
217
				var input = new TextBox({
218
					value: option.value
219
				});
220
				var inputRetype = new TextBox({
221
					value: option.value,
222
					id: option.id,
223
					isValid: function() {
224
						return input.get('value') ===
225
							this.get('value');
226
					},
227
					invalidMessage: _('The entries do not match, please retype again.')
228
				});
229
				put(optionNode, input.domNode);
230
				put(optionNode, inputRetype.domNode);
231
				put(step, optionNode);
232
				return {
233
					id: option.id,
234
					getValue: function() { return inputRetype.get('value');},
235
					isValid: function() { return inputRetype.isValid();}
236
				};
237
			});
238
			this._saveButton = new Button({
239
				label: _('Save'),
240
				onClick: lang.hitch(this, '_setContactInformation')
241
			});
242
			put(step, this._saveButton.domNode);
243
244
			this._cancelButton = new Button({
245
				label: _('Cancel'),
246
				onClick: lang.hitch(this, '_deleteRenewOptions')
247
			});
248
			put(step, this._cancelButton.domNode);
249
			put(this.steps, step);
250
		},
251
252
		/**
253
		 * Send renew options to the server.
254
		 * */
255
		_setContactInformation: function() {
256
			this._cancelButton.set('disabled', true);
257
			this._saveButton.set('disabled', true);
258
259
			var allOptionsAreValid = array.some(this._renewInputs, function(input){
260
				return input.isValid();
261
			});
262
			
263
			//var isValidMail = this._validateMail(data.email);
264
			if (allOptionsAreValid) {
265
				data = this._getNewContactInformation();
266
				xhr.post('passwordreset/set_contact', {
267
						handleAs: 'json',
268
						headers: {
269
							'Content-Type': 'application/json',
270
							'Accept-Language': lib.getQuery('lang') || 'en-US'
271
						},
272
						data: json.stringify(data)
273
					}).then(lang.hitch(this, function(data) {
274
						lib.showLastMessage({
275
							content: data.message,
276
							'class': '.success'
277
						});
278
						this._deleteRenewOptions();
279
					}), lang.hitch(this, function(err){
280
						var message = err.name + ": " + err.message;
281
						if (err.response && err.response.data && err.response.data.message) {
282
							message = err.response.data.message;
283
						}
284
						lib.showMessage({
285
							content: message,
286
							'class': '.error'
287
						});
288
						this._cancelButton.set('disabled', false);
289
						this._saveButton.set('disabled', false);
290
					}));
291
			} else {
292
				this._cancelButton.set('disabled', false);
293
				this._saveButton.set('disabled', false);
294
			}
295
		},
296
297
		/**
298
		 * Gets current renew options and credentials.
299
		 * */
300
		_getNewContactInformation: function() {
301
			var contactInformation = {
302
				'username': this._username.get('value'),
303
				'password': this._password.get('value')
304
			};
305
			array.forEach(this._renewInputs, function(input){
306
				contactInformation[input.id] = input.getValue();
307
			});
308
309
			// ugly hack because the backend urgently needs an empty string
310
			// for mail and for mobile
311
			array.forEach(['email', 'mobile'], function(key) {
312
				if (!contactInformation[key]) {
313
					contactInformation[key] = '';
314
				}
315
			});
316
			return contactInformation;
317
		},
318
319
		/**
320
		 * Validates given email address.
321
		 * */
322
		_validateMail: function(email) {
323
			var reg = /^([\w\-]+(?:\.[\w\-]+)*)@((?:[\w\-]+\.)*\w[\w\-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
324
			var isValid = !email.length || reg.test(email);
325
			if(!isValid) {
326
				lib.showMessage({
327
					content: _('Please enter a valid email address.'),
328
					'class': '.error'
329
				});
330
			}
331
			return isValid;
332
		},
333
334
		/**
335
		 * Delets renew options node.
336
		 * */
337
		_deleteRenewOptions: function() {
338
			put(this._renewOptions, '!');
339
			put(this._showContactInformationButton.domNode, '!dijitHidden');
340
			this._showContactInformationButton.set('disabled', false);
341
			this._username.reset();
342
			this._password.reset();
343
		}
344
	};
345
});
(-)a/management/univention-self-service/js/ucs/TextBox.js (-114 / +6 lines)
 Lines 30-155    Link Here 
30
30
31
define([
31
define([
32
	"dojo/_base/declare",
32
	"dojo/_base/declare",
33
	"dojo/_base/lang",
33
	"dijit/form/ValidationTextBox"
34
	"put-selector/put",
34
], function(declare, ValidationTextBox) {
35
	"dojo/on",
35
	return declare("selfservice.password.TextBox", [ ValidationTextBox ], {
36
	"dojo/when",
37
	"dijit/form/ValidationTextBox",
38
	"./LabelPane",
39
	"./_FormWidgetMixin"
40
	//"umc/tools"
41
], function(declare, lang, put, on, when, ValidationTextBox, LabelPane, _FormWidgetMixin) {
42
	return declare("umc.widgets.TextBox", [ ValidationTextBox, _FormWidgetMixin ], {
43
		// dynamicValue: String|Function
44
		//		Either an UMCP command to query a value from or a javascript function.
45
		//		The javascript function may return a String or a dojo/Deferred object.
46
		dynamicValue: null,
47
48
		// depends: String?|String[]?
49
		//		Specifies that values need to be loaded dynamically depending on
50
		//		other form fields.
51
		depends: null,
52
53
		// umcpCommand:
54
		//		Reference to the umcpCommand the widget should use.
55
		//		In order to make the widget send information such as module flavor
56
		//		etc., it can be necessary to specify a module specific umcpCommand
57
		//		method.
58
		//umcpCommand: lang.hitch(tools, 'umcpCommand'),
59
60
		// inlineLabel: String
61
		//		If specified, the given string ias positioned as label above the input field.
62
		inlineLabel: null,
63
		_inlineLabelNode: null,
64
		label: null,
65
66
		_createInlineLabelNode: function(value) {
67
			this._inlineLabelNode = put(this.focusNode, '-span.umcInlineLabel', value);
68
			this.own(on(this._inlineLabelNode, 'click', lang.hitch(this, 'focus')));
69
		},
70
71
		reset: function() {
72
			this.set('value', '');
73
			this.set('disabled', false);
74
			this.setValid();
75
			if (this.inlineLabel && this._inlineLabelNode) {
76
				this._updateInlineLabelVisibility();
77
			}
78
		},
79
80
		_updateInlineLabelVisibility: function(eventType) {
81
			var showInlineLabel = !this.get('value') && eventType != 'keydown';
82
			put(this._inlineLabelNode, showInlineLabel ? '.umcEmptyValue' : '!umcEmptyValue');
83
		},
84
85
		_registerInlineLabelEvents: function() {
86
			this.on('keydown', lang.hitch(this, '_updateInlineLabelVisibility', 'keydown'));
87
			this.on('click', lang.hitch(this, '_updateInlineLabelVisibility', 'keydown'));
88
			this.on('focus', lang.hitch(this, '_updateInlineLabelVisibility', 'focus'));
89
			this.on('blur', lang.hitch(this, '_updateInlineLabelVisibility', 'blur'));
90
		},
91
92
		_setInlineLabelAttr: function(value) {
93
			if (!this._inlineLabelNode) {
94
				return;
95
			}
96
97
			// update node content
98
			put(this._inlineLabelNode, '', {
99
				innerHTML: value
100
			});
101
102
			// notify observers
103
			this._set('inlineLabel', value);
104
		},
105
36
106
		buildRendering: function() {
37
		buildRendering: function() {
107
			this.inherited(arguments);
38
			this.inherited(arguments);
108
			if (this.inlineLabel !== null) {
109
				this._createInlineLabelNode(this.inlineLabel);
110
				this._registerInlineLabelEvents();
111
				this._updateInlineLabelVisibility();
112
			}
113
			if (this.label !== undefined) {
114
				this.label = new LabelPane({
115
					content: this,
116
					'class': this['class']
117
				});
118
				this.set('class', '');
119
			}
120
			this.tooltipPosition = ['after', 'below'];
39
			this.tooltipPosition = ['after', 'below'];
121
		},
40
		},
122
41
123
		//FIXME: the name should be different from _loadValues, e.g., _dependencyUpdate,
42
		reset: function() {
124
		//       and the check for all met dependencies should be done in the Form
43
			this.set('value', '');
125
//		_loadValues: function(/*Object?*/ params) {
44
			this.set('disabled', false);
126
//			// mixin additional options for the UMCP command
127
//			if (this.dynamicOptions && typeof this.dynamicOptions == "object") {
128
//				lang.mixin(params, this.dynamicOptions);
129
//			}
130
//
131
//			// get the dynamic values, block concurrent events for value loading
132
//			var func = tools.stringOrFunction(this.dynamicValue, this.umcpCommand);
133
//			var deferredOrValues = func(params);
134
//
135
//			// make sure we have an array or a dojo/Deferred object
136
//			if (deferredOrValues) {
137
//				when(deferredOrValues, lang.hitch(this, function(res) {
138
//					this.set('value', res);
139
//				}));
140
//			}
141
//		},
142
143
		// this seems to be necessary for IE8:
144
		// https://forge.univention.org/bugzilla/show_bug.cgi?id=28498
145
		_getValueAttr: function() {
146
			var val = this.inherited(arguments);
147
			if (val === '') {
148
				// seriously! at least it should not break anything...
149
				// although val === '', json.stringify returns ""null"" in IE8
150
				val = '';
151
			}
152
			return val;
153
		}
45
		}
154
	});
46
	});
155
});
47
});
(-)a/management/univention-self-service/js/ucs/de.po (-140 / +56 lines)
 Lines 3-9   msgid "" Link Here 
3
msgstr ""
3
msgstr ""
4
"Project-Id-Version: univention-apache\n"
4
"Project-Id-Version: univention-apache\n"
5
"Report-Msgid-Bugs-To: packages@univention.de\n"
5
"Report-Msgid-Bugs-To: packages@univention.de\n"
6
"POT-Creation-Date: 2015-11-19 09:19+0100\n"
6
"POT-Creation-Date: 2016-04-01 13:30+0200\n"
7
"PO-Revision-Date: 2016-01-14 11:26+0100\n"
7
"PO-Revision-Date: 2016-01-14 11:26+0100\n"
8
"Last-Translator: Univention GmbH <packages@univention.de>\n"
8
"Last-Translator: Univention GmbH <packages@univention.de>\n"
9
"Language-Team: Univention GmbH <packages@univention.de>\n"
9
"Language-Team: Univention GmbH <packages@univention.de>\n"
 Lines 12-22   msgstr "" Link Here 
12
"Content-Type: text/plain; charset=UTF-8\n"
12
"Content-Type: text/plain; charset=UTF-8\n"
13
"Content-Transfer-Encoding: 8bit\n"
13
"Content-Transfer-Encoding: 8bit\n"
14
14
15
msgid " If you already have a token you can <a>skip this step</a>."
15
msgid " (retype)"
16
msgstr " Wenn Sie bereits über einen Token verfügen, dann können Sie <a>diesen Schritt überspringen</a>."
16
msgstr " (Wiederholung)"
17
18
msgid " If your token has expired you can <a>request a new token</a>."
19
msgstr " Wenn Ihr Token abgelaufen ist, können Sie einen <a>neuen Token anfordern</a>."
20
17
21
msgid "</br><a href='/{0}'>Back to the overview.</a>"
18
msgid "</br><a href='/{0}'>Back to the overview.</a>"
22
msgstr "</br><a href='/{0}'>Zurück zur Übersicht.</a>"
19
msgstr "</br><a href='/{0}'>Zurück zur Übersicht.</a>"
 Lines 24-46   msgstr "</br><a href='/{0}'>Zurück zur Übersicht.</a>" Link Here 
24
msgid "</br><div>You will be redirected {0} in <a id='redirectTimer'> {1} </a> second(s).</div>"
21
msgid "</br><div>You will be redirected {0} in <a id='redirectTimer'> {1} </a> second(s).</div>"
25
msgstr "</br><div>Sie werden in <a id='redirectTimer'> {1} </a> Sekunden {0} weitergeleitet.</div>"
22
msgstr "</br><div>Sie werden in <a id='redirectTimer'> {1} </a> Sekunden {0} weitergeleitet.</div>"
26
23
24
msgid "Activate renew options."
25
msgstr "Wiederherstellungsoptionen aktivieren."
26
27
msgid "Cancel"
27
msgid "Cancel"
28
msgstr "Abbrechen"
28
msgstr "Abbrechen"
29
29
30
msgid "Change Password"
31
msgstr "Passwort ändern"
32
33
msgid "Change password"
30
msgid "Change password"
34
msgstr "Passwort ändern"
31
msgstr "Passwort ändern"
35
32
36
msgid "Contact information for Password reset"
33
msgid "Change your (expired) password."
37
msgstr "Kontaktinformationen zum Zurücksetzen des Passworts"
34
msgstr "Ändern Sie Ihr (abgelaufenes) Passwort."
38
35
39
msgid "EMail"
36
msgid "Everyone forgets their password now and then. Protect yourself and activate the opportunity to set a new password."
40
msgstr "E-Mail"
37
msgstr "Jeder vergißt mal das Passwort. Schützen Sie sich und aktivieren Sie die Möglichkeit ihr Passwort erneuern zu können."
41
38
42
msgid "Feel free to change your contact information. Press \"Save\" to confirm your changes."
39
msgid "Forbidden chars:"
43
msgstr "Bitte tragen Sie Ihre Kontaktinformationen ein und drücken Sie anschließend \"Speichern\", um Ihre Änderungen zu bestätigen."
40
msgstr "Vorbotene Zeichen:"
44
41
45
msgid ""
42
msgid ""
46
"Forbidden redirect to: {0}\n"
43
"Forbidden redirect to: {0}\n"
 Lines 49-54   msgstr "" Link Here 
49
"Verbotene Weiterleitung nach: {0}\n"
46
"Verbotene Weiterleitung nach: {0}\n"
50
" Die URL muss mit (nur) einem \"/\" beginnen."
47
" Die URL muss mit (nur) einem \"/\" beginnen."
51
48
49
msgid "Forgot your password? Set a new one: "
50
msgstr "Haben Sie ihr Passwort vergessen? Setzen Sie ein Neues:"
51
52
#, python-format
52
#, python-format
53
msgid "Hello %(last)s, %(first)s!"
53
msgid "Hello %(last)s, %(first)s!"
54
msgstr "Hallo %(last)s, %(first)s!"
54
msgstr "Hallo %(last)s, %(first)s!"
 Lines 57-125   msgstr "Hallo %(last)s, %(first)s!" Link Here 
57
msgid "Hello %s %s!"
57
msgid "Hello %s %s!"
58
msgstr "Hallo %s %s!"
58
msgstr "Hallo %s %s!"
59
59
60
msgid "If you did not received an e-mail please check your spam directory or use this link to go back to step 2."
61
msgstr "Sollten Sie keine E-Mail erhalten haben, dann prüfen Sie bitte Ihr SPAM-Verzeichnis oder nutzen Sie diesen Link und kehren zu Schritt 2 zurück."
62
60
msgid "Language"
63
msgid "Language"
61
msgstr "Sprache"
64
msgstr "Sprache"
62
65
63
msgid "Mobile"
66
msgid "New Password"
64
msgstr "Mobilfunknummer"
65
66
msgid "New password"
67
msgstr "Neues Passwort"
67
msgstr "Neues Passwort"
68
68
69
msgid "New password (retype)"
69
msgid "New Password (retype)"
70
msgstr "Neues Passwort (Wiederholung)"
70
msgstr "Neues Passwort (Wiederholung)"
71
71
72
msgid "Next"
72
msgid "Next"
73
msgstr "Weiter"
73
msgstr "Weiter"
74
74
75
msgid "Old password"
75
msgid "Old Password"
76
msgstr "Altes Passwort"
76
msgstr "Altes Passwort"
77
77
78
msgid "On this page you can change your password. If you have lost your password, use this link to the <a href=\"/univention-self-service/{0}#passwordreset\">password reset</a> page."
79
msgstr "Auf dieser Seite können Sie Ihr Passwort ändern. Wenn Sie Ihr Passwort vergessen haben, nutzen Sie bitte den folgenden Link: <a href=\"/univention-self-service/{0}#passwordreset\">Passwort zurücksetzen.</a>"
80
81
msgid "On this page you can reset your lost password or provide contact information for setting a new password in the future."
82
msgstr "Auf dieser Seite können Sie Ihr Passwort zurücksetzen oder Ihre Kontaktinformationen angeben, um zukünftig Ihr Passwort zurücksetzen zu können."
83
84
msgid "On this page you can set your contact information to reset your password in the future. During the reset process a token is sent to you. Without contact information it is not possible to reset your password."
85
msgstr "Auf dieser Seite können Sie Ihre Kontaktinformationen angeben. Diese Informationen werden benötigt, um Ihnen einen Token (Sicherheitsschlüssel) zuzusenden. Nur mit Hilfe eines Tokens ist es möglich das Passwort zurückzusetzen."
86
87
msgid "Password"
78
msgid "Password"
88
msgstr "Passwort"
79
msgstr "Passwort"
89
80
90
msgid "Password Reset"
81
msgid "Password change"
91
msgstr "Passwort zurücksetzen"
82
msgstr "Passwort ändern"
92
83
93
msgid "Please choose a method to receive the token."
84
msgid "Password forgotten"
94
msgstr "Bitte wählen Sie eine Benachrichtigungsart über die Sie einen Token (Sicherheitsschlüssel) erhalten möchten."
85
msgstr "Passwort vergessen"
95
86
96
msgid "Please click the following link to <a href=\"/univention-self-service/{0}#setcontactinformation\">change your contact information</a> for resetting your password in the future."
87
msgid "Please choose an option to renew your password."
97
msgstr "Bitte nutzen Sie den folgenden Link, um Ihre <a href=\"/univention-self-service/{0}#setcontactinformation\">  Kontaktinformationen zu ändern</a> damit Sie zukünftig Ihr Passwort zurücksetzen können."
88
msgstr "Bitte wählen Sie eine Wiederherstellungsoption aus."
98
89
99
msgid "Please enter a valid email address."
90
msgid "Please enter a valid email address."
100
msgstr "Keine gültige E-Mail-Adresse."
91
msgstr "Keine gültige E-Mail-Adresse."
101
92
102
msgid "Please enter the token and your new password."
93
msgid "Protect Account Access"
103
msgstr "Bitte geben Sie den Token (Sicherheitsschlüssel) und ein neues Passwort ein."
94
msgstr "Kontozugang schützen"
104
95
105
msgid "Please enter your username and password to display your contact information."
96
msgid "Required chars:"
106
msgstr "Bitte geben Sie Ihren Benutzernamen und Ihr Passwort ein, um Ihre Kontaktinformationen einsehen und ändern zu können."
97
msgstr "Erforderliche Zeichen:"
107
98
108
msgid "Please provide the required data to change your password."
99
msgid "Required length:"
109
msgstr "Bitte geben Sie die notwendigen Daten ein, um Ihr Passwort zu ändern."
100
msgstr "Erforderliche Passwortlänge:"
110
101
111
msgid "Please provide your username to receive a token that is required to reset your password."
102
msgid "Required number of lower case letters:"
112
msgstr "Bitte geben Sie Ihren Benutzernamen ein. Sie erhalten anschließend einen Token (Sicherheitsschlüssel) mit dem Sie Ihr Passwort zurücksetzen können."
103
msgstr "Erforderliche Anzahl von Kleinbuchstaben:"
113
104
114
msgid "Provide your contact information."
105
msgid "Required number of special characters (nor digit or letters):"
115
msgstr "Geben Sie Ihre Kontaktinformationen an."
106
msgstr "Erforderliche Anzahl von Sonderzeichen:"
116
107
117
msgid "Reset your password."
108
msgid "Required number of upper case letters:"
118
msgstr "Passwort zurücksetzen."
109
msgstr "Erforderliche Anzahl von Großbuchstaben:"
119
110
120
msgid "Save"
111
msgid "Save"
121
msgstr "Speichern"
112
msgstr "Speichern"
122
113
114
msgid "Set a new password!"
115
msgstr "Setzen Sie ein neues Passwort!"
116
117
msgid "The entries do not match, please retype again."
118
msgstr "Die Eingaben stimmen nicht überein. Bitte versuchen Sie es erneut."
119
120
msgid "The password must fullfill following conditions:"
121
msgstr "Das Passwort muss folgende Bedingungen erfüllen:"
122
123
msgid "The passwords do not match, please retype again."
123
msgid "The passwords do not match, please retype again."
124
msgstr "Die Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut."
124
msgstr "Die Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut."
125
125
 Lines 127-134   msgstr "Die Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut." Link Here 
127
msgid "The total cost was %.2f EUR!"
127
msgid "The total cost was %.2f EUR!"
128
msgstr "Die Gesamtkosten waren %.2f EUR!"
128
msgstr "Die Gesamtkosten waren %.2f EUR!"
129
129
130
msgid "Token"
130
msgid "This value is required."
131
msgstr "Token (Sicherheitsschlüssel)"
131
msgstr "Pflichtfeld."
132
132
133
msgid "Translate me!"
133
msgid "Translate me!"
134
msgstr "Übersetz mich!"
134
msgstr "Übersetz mich!"
 Lines 136-230   msgstr "Übersetz mich!" Link Here 
136
msgid "Username"
136
msgid "Username"
137
msgstr "Benutzername"
137
msgstr "Benutzername"
138
138
139
msgid "to '{0}'"
139
msgid "We have send you an e-mail to your alternative e-mail address, that you have provided on the page \"Protect Account Access\". Please check your mails and follow the link to renew your password."
140
msgstr "zu '{0}'"
140
msgstr "Wir haben Ihnen eine E-Mail an Ihre alternative E-Mailadresse geschickt. Diese haben Sie auf der Seite \"Kontugang schützen\" hinterlegt. Bitte prüfen Sie Ihre E-Mails und folgen Sie den Link, um Ihr Passwort zu erneuern."
141
142
#~ msgid "A license file has been sent to <strong id=\"email-address\">{0}</strong>. This file is necessary to activate the system. For this, please carry out the following steps: <ol><li>Open the email.</li><li>Save the attachement (ucs.license) on your computer.</li><li>Click the button 'Upload license file'.</li><li>Select the file (ucs.license) you just saved.</li><li>Confirm the selection.</li></ol>Once the activation has been finished your email address will be sent to the app provider. The app provider may contact you."
143
#~ msgstr "Eine Lizenzdatei wurde an <strong id=\"email-address\">{0}</strong> gesendet. Sie wird benötigt um das System zu aktivieren. Bitte führen Sie dazu folgende Schritte aus: <ol><li>Öffnen Sie die E-Mail.</li><li>Speichern Sie den Anhang (ucs.license) auf Ihren Computer.</li><li>Klicken Sie auf die Schaltfläche 'Lizenzdatei hochladen'.</li><li>Wählen Sie die soeben gespeicherte Datei (ucs.license) aus.</li><li>Bestätigen Sie die Auswahl.</li></ol> Sobald die Aktivierung durchgeführt ist, wird Ihre E-Mail-Adresse an den App-Anbieter weitergeleitet. Der App-Anbieter wird Sie ggf. kontaktieren."
144
145
#~ msgid "Activation of {appliance_name} Univention App"
146
#~ msgstr "Aktivierung von {appliance_name} Univention App"
147
148
#~ msgid "Activation successful!"
149
#~ msgstr "Aktivierung erfolgreich!"
150
151
#~ msgid "An unknown error has occurred."
152
#~ msgstr "Ein unbekannter Fehler trat auf."
153
154
#~ msgid "An unknown error occured. Please try it again later!"
155
#~ msgstr "Ein unbekannter Fehler trat auf. Bitte versuchen sie es später noch einmal!"
156
157
#~ msgid "Confirm username"
158
#~ msgstr "Benutzername bestätigen"
159
160
#~ msgid "Continue"
161
#~ msgstr "Weiter"
162
141
163
#~ msgid "E-mail address"
142
msgid "You have mail!"
164
#~ msgstr "E-Mail-Adresse"
143
msgstr "Sie haben eine neue E-Mail!"
165
144
166
#~ msgid "Error "
145
msgid "to '{0}'"
167
#~ msgstr "Fehler "
146
msgstr "zu '{0}'"
168
169
#~ msgid "I have forgotten my password."
170
#~ msgstr "Ich habe mein Passwort vergessen."
171
172
#~ msgid "I want to change my (expired) password."
173
#~ msgstr "Ich will mein (abgelaufenes) Passwort ändern."
174
175
#~ msgid "I would like to set my contact information for resetting my password."
176
#~ msgstr "Ich möchte meine Kontaktinformationen ändern, um zukünftig mein Password  zurücksetzen zu können."
177
178
#~ msgid "If you did not receive an email, please check your SPAM directory or <a href=\"#register\"> request the email again</a>."
179
#~ msgstr "Sollten Sie keine E-Mail erhalten haben, prüfen Sie Ihr SPAM-Verzeichnis oder <a href=\"#register\">fordern Sie die Lizenzdatei noch einmal an</a>."
180
181
#~ msgid "If you encounter problems during the activation, please send an email to: <strong><a href=\"mailto:feedback@univention.de\" style=\"color:#000\">feedback@univention.de</a></strong>"
182
#~ msgstr "Sollten Probleme bei der Aktivierung auftreten, senden Sie bitte eine E-Mail an: <strong><a href=\"mailto:feedback@univention.de\" style=\"color:#000\">feedback@univention.de</a></strong>"
183
184
#~ msgid "In order to reset your password please carry out the following steps: "
185
#~ msgstr "Um Ihr Passwort zurückzusetzen führen Sie bitte die folgenden Schritte aus: "
186
187
#~ msgid "License request."
188
#~ msgstr "Anforderung einer Lizenz."
189
190
#~ msgid "More details about the activation can be found in the <a href=\"http://docs.univention.de/manual.html#central:license\" target=\"_blank\">UCS manual</a>."
191
#~ msgstr "Weitere Informationen zu der Aktivierung können im <a href=\"http://docs.univention.de/handbuch.html#central:license\" target=\"_blank\">UCS-Handbuch</a> gefunden werden."
192
193
#~ msgid "Password self-service"
194
#~ msgstr "Passwort verwalten"
195
196
#~ msgid "Please enter a valid email address in order to activate {appliance_name} Univention App. The activation is mandatory to deploy the system. In the next step you can upload the license file that has been sent to your email address."
197
#~ msgstr "Bitte geben Sie eine gültige E-Mail-Adresse ein, um {appliance_name} Univention App zu aktivieren. Die Aktivierung ist Voraussetzung, um das System in Gebrauch zu nehmen. Im nächsten Schritt können sie die Lizenzdatei hochladen, die an Ihre E-Mail-Adresse gesendet wurde."
198
199
#~ msgid "Please enter your username."
200
#~ msgstr "Bitte geben Sie Ihren Benutzernamen ein."
201
202
#~ msgid "Request token"
203
#~ msgstr "Token anfordern"
204
205
#~ msgid "Show contact information"
206
#~ msgstr "Kontaktinformationen anzeigen"
207
208
#~ msgid "The following error occurred:"
209
#~ msgstr "Der folgende Fehler trat auf:"
210
211
#~ msgid "The server is not responding. Please restart the system."
212
#~ msgstr "Der Webserver antwortet nicht. Bitte starten Sie das System neu."
213
214
#~ msgid "Upload license file"
215
#~ msgstr "Lizenzdatei hochladen"
216
217
#~ msgid "Welcome to the Password self-service. On this site you can reset and change your password. Please select an option to get more information."
218
#~ msgstr "Willkommen zur Passwortverwaltung. Auf dieser Seite können Sie Ihr Passwort  zurücksetzen oder ändern. Bitte wählen Sie eine Option, um mehr Informationen  zu erhalten."
219
220
#~ msgid "You have got mail!"
221
#~ msgstr "Sie haben eine neue E-Mail!"
222
223
#~ msgid "You have received a license file by email!"
224
#~ msgstr "Sie haben eine Lizendatei per E-Mail erhalten!"
225
226
#~ msgid "your email address"
227
#~ msgstr "Ihre E-Mail-Adresse"
228
229
#~ msgid "{appliance_name} Univention App is now activated. Click \"Continue\" to access the management interface (which may take a while)."
230
#~ msgstr "{appliance_name} Univention App ist nun aktiviert. Klicken sie auf \"Weiter\", um auf die Verwaltungsoberfläche zuzugreifen. (Das kann einige Zeit benötigen.)"
(-)a/management/univention-self-service/js/ucs/lib.js (-9 / +48 lines)
 Lines 36-51   define([ Link Here 
36
	"dojo/io-query",
36
	"dojo/io-query",
37
	"dojox/html/entities",
37
	"dojox/html/entities",
38
	"put-selector/put",
38
	"put-selector/put",
39
	"dojo/request",
39
	"./i18n!."
40
	"./i18n!."
40
], function(lang, fx, dom, domGeom, ioQuery, htmlEntities, put, _) {
41
], function(lang, fx, dom, domGeom, ioQuery, htmlEntities, put, request, _) {
41
42
42
	return {
43
	return {
43
		getCurrentLanguageQuery: function() {
44
		getCurrentLanguageQuery: function() {
44
			return '?lang=' + (this.getQuery('lang') || 'en-US');
45
			return '?lang=' + (this.getQuery('lang') || 'en-US');
45
		},
46
		},
46
47
48
		/**
49
		 * Displays given message.
50
		 * @param {object} msg - Provides targetNode, class and content
51
		 * for the message.
52
		 */
47
		showMessage: function(msg) {
53
		showMessage: function(msg) {
48
			var targetNode = msg.targetNode || dom.byId("content");
54
			var targetNode = msg.targetNode || dom.byId("server_msg");
49
			var msgNode = dom.byId('msg');
55
			var msgNode = dom.byId('msg');
50
56
51
			if (msgNode) {
57
			if (msgNode) {
 Lines 64-70   define([ Link Here 
64
		},
70
		},
65
71
66
		showLastMessage: function(msg) {
72
		showLastMessage: function(msg) {
67
			var targetNode = msg.targetNode || dom.byId("title");
73
			var targetNode = msg.targetNode || dom.byId("server_msg");
68
			var msgNode = dom.byId('msg');
74
			var msgNode = dom.byId('msg');
69
75
70
			if (msgNode) {
76
			if (msgNode) {
 Lines 107-128   define([ Link Here 
107
			return message;
113
			return message;
108
		},
114
		},
109
115
116
		/**
117
		 * Returns relative url from query string.
118
		 */
110
		_getUrlForRedirect: function() {
119
		_getUrlForRedirect: function() {
111
			var queryUrl = this.getQuery('url');
120
			var queryUrl = this.getQuery('url');
112
			if (queryUrl) {
121
			if (queryUrl) {
113
				// checking if queryUrl is relative = has to start wit only one '/'
122
				if (this._isUrlRelative(queryUrl)) {
114
				var reg = /^\/([^\/]|$)/;
115
				var isUrlRelative = reg.test(queryUrl);
116
				if (isUrlRelative) {
117
					return queryUrl;
123
					return queryUrl;
118
				} else {
124
				} else {
119
					// forbidden to provide absolute urls
125
					var msg = {
120
					console.error(lang.replace(_('Forbidden redirect to: {0}\n The url has to start with (only) one "/".', [queryUrl])));
126
						content: lang.replace(_('Forbidden redirect to: {0}\n The url has to start with (only) one "/".', [queryUrl])),
127
						'class': 'error'
128
					};
129
					this.showMessage(msg);
121
				}
130
				}
122
			}
131
			}
123
			return;
132
			return;
124
		},
133
		},
125
134
135
		/** Returns boolean if given url is relative.
136
		 * @param {string} url - url to test
137
		 * */
138
		_isUrlRelative: function(url) {
139
				var reg = /^\/([^\/]|$)/;
140
				var isUrlRelative = reg.test(url);
141
				return isUrlRelative;
142
		},
143
126
		_getUrlLabelForRedirect: function() {
144
		_getUrlLabelForRedirect: function() {
127
			var label = this.getQuery('urlLabel');
145
			var label = this.getQuery('urlLabel');
128
			if (label) {
146
			if (label) {
 Lines 133-138   define([ Link Here 
133
			}
151
			}
134
		},
152
		},
135
153
154
		/**
155
		 * Returns the value of the query string for a given key.
156
		 * */
136
		getQuery: function(key) {
157
		getQuery: function(key) {
137
			var queryString = window.location.search.substring(1);
158
			var queryString = window.location.search.substring(1);
138
			var queryObject = ioQuery.queryToObject(queryString);
159
			var queryObject = ioQuery.queryToObject(queryString);
 Lines 146-151   define([ Link Here 
146
			}
167
			}
147
		},
168
		},
148
169
170
		/**
171
		 * Returns the needed backend information for the Password Service
172
		 * as a promise or as an object.
173
		 * The information is requested once and will be cached in
174
		 * this._backend_info.
175
		 * */
176
		getBackendInformation: function() {
177
			if (!this._backend_info) {
178
				var promise = request.get("/univention-self-service/entries.json");
179
				promise.then(lang.hitch(this, function(data){
180
					this._backend_info = data;
181
				}));
182
				return promise;
183
			} else {
184
				return this._backend_info;
185
			}
186
		},
187
149
		wipeInNode: function(conf) {
188
		wipeInNode: function(conf) {
150
			var endHeight = domGeom.getMarginBox(conf.node).h;
189
			var endHeight = domGeom.getMarginBox(conf.node).h;
151
			fx.animateProperty({
190
			fx.animateProperty({
(-)a/management/univention-self-service/js/ucs/passwordchange.js (-209 lines)
 Lines 1-209    Link Here 
1
/*
2
 * Copyright 2015-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
/*global define require console window */
30
31
define([
32
	"dojo/_base/lang",
33
	"dojo/on",
34
	"dojo/keys",
35
	"dojo/dom",
36
	"dojo/json",
37
	"dojo/request/xhr",
38
	"dijit/form/Button",
39
	"put-selector/put",
40
	"./TextBox",
41
	"./LabelPane",
42
	"./lib",
43
	"./i18n!."
44
], function(lang, on, keys, dom, json, xhr, Button, put, TextBox, LabelPane, lib, _) {
45
46
	return {
47
		_createTitle: function() {
48
			var title = _('Change Password');
49
			var siteDescription = lang.replace(_('On this page you can change your password. If you have lost your password, use this link to the <a href="/univention-self-service/{0}#passwordreset">password reset</a> page.', [lib.getCurrentLanguageQuery()]));
50
			document.title = title;
51
			var titleNode = dom.byId('title');
52
			put(titleNode, 'h1', title);
53
			put(titleNode, 'p', { innerHTML : siteDescription });
54
			put(titleNode, '!.dijitHidden');
55
		},
56
57
		_createContent: function() {
58
			var contentNode = dom.byId('content');
59
			var formNode = this._getFormNode();
60
			put(formNode, '[id=form]!dijitHidden');
61
			put(contentNode, formNode);
62
		},
63
64
		_getFormNode: function() {
65
			var formNode = put('div.step');
66
			put(formNode, 'p > b', _('Please provide the required data to change your password.'));
67
			var stepContent = put(formNode, 'div.stepContent');
68
69
			// create input field for username
70
			this._username = new TextBox({
71
				label: _('Username'),
72
				'class': 'doubleLabelPane block',
73
				isValid: function() {
74
					return !!this.get('value');
75
				},
76
				required: true
77
			});
78
			put(stepContent, '>', this._username.label.domNode);
79
			this._username.startup();
80
81
			// create input field for old password
82
			this._oldPassword = new TextBox({
83
				label: _('Old password'),
84
				type: 'password',
85
				'class': 'doubleLabelPane block',
86
				isValid: function() {
87
					return !!this.get('value');
88
				},
89
				required: true
90
			});
91
			put(stepContent, '>', this._oldPassword.label.domNode);
92
			this._oldPassword.startup();
93
94
			// create input fields for new password
95
			this._newPassword = new TextBox({
96
				label: _('New password'),
97
				type: 'password',
98
				'class': 'doubleLabelPane left',
99
				isValid: function() {
100
					return !!this.get('value');
101
				},
102
				required: true
103
			});
104
			put(stepContent, '>', this._newPassword.label.domNode);
105
			this._newPassword.startup();
106
107
			// create input fields for new password
108
			this._verifyPassword = new TextBox({
109
				label: _('New password (retype)'),
110
				type: 'password',
111
				'class': 'doubleLabelPane',
112
				isValid: lang.hitch(this, function() {
113
					return this._newPassword.get('value') ===
114
						this._verifyPassword.get('value');
115
				}),
116
				invalidMessage: _('The passwords do not match, please retype again.'),
117
				required: true
118
			});
119
			put(stepContent, '>', this._verifyPassword.label.domNode);
120
			this._verifyPassword.startup();
121
122
			// create submit button
123
			this._submitButton = new Button({
124
				label: _('Change password'),
125
				onClick: lang.hitch(this, '_submit')
126
			});
127
			put(stepContent, '>', this._submitButton.domNode);
128
129
			// let the user submit form by pressing ENTER
130
			on(document, "keyup", lang.hitch(this, function(evt) {
131
				if (evt.keyCode === keys.ENTER && !this._submitButton.get('disabled')) {
132
					this._submit();
133
				}
134
			}));
135
136
			return formNode;
137
		},
138
139
		_submit: function() {
140
			this._showValidStatusOfInputFields();
141
			this._submitButton.set('disabled', true);
142
			var allInputFieldsAreValid = this._username.isValid() &&
143
				this._oldPassword.isValid() &&
144
				this._newPassword.isValid() &&
145
				this._verifyPassword.isValid();
146
147
			if (allInputFieldsAreValid) {
148
				data = json.stringify({
149
					password: {
150
						'username': this._username.get('value'),
151
						'password': this._oldPassword.get('value'),
152
						'new_password': this._newPassword.get('value')
153
					}
154
				});
155
156
				xhr.post('/univention-management-console/set', {
157
					handleAs: 'json',
158
					headers: {
159
						'Content-Type': 'application/json',
160
						'Accept-Language': lib.getQuery('lang') || 'en-US'
161
					},
162
					data: data
163
				}).then(lang.hitch(this, function(data) {
164
					lib._removeMessage();
165
					var callback = function() {
166
						lib.showLastMessage({
167
							content: data.message,
168
							'class': '.success'
169
						});
170
					};
171
					lib.wipeOutNode({
172
						node: dom.byId('form'),
173
						callback: callback
174
					});
175
					this._clearAllInputFields();
176
				}), lang.hitch(this, function(err) {
177
					var message = err.name + ": " + err.message;
178
					if (err.response && err.response.data && err.response.data.message) {
179
						message = err.response.data.message;
180
					}
181
					lib.showMessage({content: message, 'class': '.error'});
182
				})).always(lang.hitch(this, function(){
183
					this._submitButton.set('disabled', false);
184
				}));
185
			} else {
186
				this._submitButton.set('disabled', false);
187
			}
188
		},
189
190
		_showValidStatusOfInputFields: function() {
191
			this._username.setValid(this._username.isValid());
192
			this._oldPassword.setValid(this._oldPassword.isValid());
193
			this._newPassword.setValid(this._newPassword.isValid());
194
			//this._verifyPassword.setValid(this._verifyPassword.isValid());
195
		},
196
197
		_clearAllInputFields: function() {
198
			this._username.reset();
199
			this._oldPassword.reset();
200
			this._newPassword.reset();
201
			this._verifyPassword.reset();
202
		},
203
204
		start: function() {
205
			this._createTitle();
206
			this._createContent();
207
		}
208
	};
209
});
(-)a/management/univention-self-service/js/ucs/passwordreset.js (-386 lines)
 Lines 1-386    Link Here 
1
/*
2
 * Copyright 2015-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
/*global define require console window */
30
31
define([
32
	"dojo/_base/lang",
33
	"dojo/_base/array",
34
	"dojo/on",
35
	"dojo/keys",
36
	"dojo/dom",
37
	"dojo/json",
38
	"dojo/request/xhr",
39
	"dijit/form/Button",
40
	"put-selector/put",
41
	"./ContainerWidget",
42
	"./LabelPane",
43
	"./TextBox",
44
	"./RadioButton",
45
	"./lib",
46
	"./i18n!."
47
], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, LabelPane, TextBox, RadioButton, lib, _) {
48
49
	return {
50
		selectedTokenMethod: null,
51
		
52
		_createTitle: function() {
53
			var title = _('Password Reset');
54
			var siteDescription = _('On this page you can reset your lost password or provide contact information for setting a new password in the future.');
55
			document.title = title;
56
			var titleNode = dom.byId('title');
57
			put(titleNode, 'h1', title);
58
			put(titleNode, 'p', siteDescription);
59
			put(titleNode, '!.dijitHidden');
60
		},
61
62
		_createContent: function() {
63
			var contentNode = dom.byId('content');
64
			var formNode = this._getFormNode();
65
			put(formNode, '[id=form].step!dijitHidden');
66
			put(contentNode, formNode);
67
			this._fillContentByUrl();
68
		},
69
70
		_getFormNode: function() {
71
			var formNode = put('div[style="overflow: hidden;"]');
72
73
			// step 1 username and link to contact information
74
			this.usernameNode = put(formNode, 'div.step');
75
			put(this.usernameNode, 'p > b', _('Reset your password.'));
76
			put(this.usernameNode, 'p', _('Please provide your username to receive a token that is required to reset your password.'));
77
			var stepContent = put(this.usernameNode, 'div.stepContent');
78
			this._username = new TextBox({
79
				label: _('Username'),
80
				'class': 'soloLabelPane',
81
				isValid: function() {
82
					return !!this.get('value');
83
				},
84
				required: true
85
			});
86
			this._username.on('keyup', lang.hitch(this, function(evt) {
87
				if (evt.keyCode === keys.ENTER) {
88
					this._getResetMethods();
89
				}
90
			}));
91
			put(stepContent, this._username.label.domNode);
92
			this._username.startup();
93
			this._usernameButton = new Button({
94
				label: _('Next'),
95
				onClick: lang.hitch(this, '_getResetMethods')
96
			});
97
			put(stepContent, this._usernameButton.domNode);
98
99
			// contact information
100
			this.contactNode = put(formNode, 'div.step');
101
			put(this.contactNode, 'p > b', _('Provide your contact information.'));
102
			put(this.contactNode, 'p', {
103
				innerHTML: lang.replace(_('Please click the following link to <a href="/univention-self-service/{0}#setcontactinformation">change your contact information</a> for resetting your password in the future.', [lib.getCurrentLanguageQuery()]))
104
			});
105
106
			// step 2 token
107
			this.tokenNode = put(formNode, 'div.step.hide-step');
108
			var skipStep = function() { 
109
				put(this.newPasswordNode, '!hide-step');
110
				put(this._requestTokenButton.domNode, '.dijitHidden');
111
				this._requestTokenButton.set('disabled', true);
112
			};
113
			var descRequestToken = put(this.tokenNode, 'p', _('Please choose a method to receive the token.'));
114
			put(descRequestToken, 'span', {
115
				innerHTML: _(' If you already have a token you can <a>skip this step</a>.'),
116
				onclick: lang.hitch(this, skipStep)
117
			});
118
			stepContent = put(this.tokenNode, 'div.stepContent');
119
			this._tokenOptions = new ContainerWidget({});
120
			put(stepContent, this._tokenOptions.domNode);
121
			this._requestTokenButton = new Button({
122
				label: _('Next'),
123
				onClick: lang.hitch(this, '_requestToken')
124
			});
125
			put(stepContent, this._requestTokenButton.domNode);
126
127
			// step 3 use the token to set a new password
128
			this.newPasswordNode = put(formNode, 'div.step.hide-step');
129
			var prevStep = function() { 
130
				put(this.newPasswordNode, '.hide-step');
131
				put(this.tokenNode, '!dijitHidden');
132
				put(this.tokenNode, '!hide-step');
133
				put(this._requestTokenButton.domNode, '!dijitHidden');
134
				this._requestTokenButton.set('disabled', false);
135
			};
136
			var descNewPassword = put(this.newPasswordNode, 'p', _('Please enter the token and your new password.'));
137
			put(descNewPassword, 'span', {
138
				innerHTML: _(' If your token has expired you can <a>request a new token</a>.'),
139
				onclick: lang.hitch(this, prevStep)
140
			});
141
			stepContent = put(this.newPasswordNode, 'div.stepContent');
142
			this._token = new TextBox({
143
				label: _('Token'),
144
				'class': 'soloLabelPane',
145
				isValid: function() {
146
					return !!this.get('value');
147
				},
148
				required: true
149
			});
150
			this._token.on('keyup', lang.hitch(this, function(evt) {
151
				if (evt.keyCode === keys.ENTER) {
152
					this._setPassword();
153
				}
154
			}));
155
			put(stepContent, this._token.label.domNode);
156
			this._token.startup();
157
158
			this._newPassword = new TextBox({
159
				label: _('New password'),
160
				type: 'password',
161
				'class': 'doubleLabelPane left',
162
				isValid: function() {
163
					return !!this.get('value');
164
				},
165
				required: true
166
			});
167
			this._newPassword.on('keyup', lang.hitch(this, function(evt) {
168
				if (evt.keyCode === keys.ENTER) {
169
					this._setPassword();
170
				}
171
			}));
172
			put(stepContent, this._newPassword.label.domNode);
173
			this._newPassword.startup();
174
175
			this._verifyPassword = new TextBox({
176
				label: _('New password (retype)'),
177
				type: 'password',
178
				'class': 'doubleLabelPane',
179
				isValid: lang.hitch(this, function() {
180
					return this._newPassword.get('value') ===
181
						this._verifyPassword.get('value');
182
				}),
183
				invalidMessage: _('The passwords do not match, please retype again.'),
184
				required: true
185
			});
186
			this._verifyPassword.on('keyup', lang.hitch(this, function(evt) {
187
				if (evt.keyCode === keys.ENTER) {
188
					this._setPassword();
189
				}
190
			}));
191
			put(stepContent, this._verifyPassword.label.domNode);
192
			this._verifyPassword.startup();
193
			this._setPasswordButton = new Button({
194
				label: _('Change password'),
195
				onClick: lang.hitch(this, '_setPassword')
196
			});
197
			put(stepContent, this._setPasswordButton.domNode);
198
			return formNode;
199
		},
200
201
		_getResetMethods: function() {
202
			this._username.set('disabled', true);
203
			this._usernameButton.set('disabled', true);
204
205
			if (this._username.isValid()) {
206
				data = json.stringify({
207
					'username': this._username.get('value')
208
				});
209
				xhr.post('passwordreset/get_reset_methods', {
210
					handleAs: 'json',
211
					headers: {
212
						'Content-Type': 'application/json',
213
						'Accept-Language': lib.getQuery('lang') || 'en-US'
214
					},
215
					data: data
216
				}).then(lang.hitch(this, function(data) {
217
					lib._removeMessage();
218
					put(this._usernameButton.domNode, '.dijitHidden');
219
					put(this.contactNode, '!');
220
					this._buildTokenOptions(data.result);
221
				}), lang.hitch(this, function(err){
222
					var message = err.name + ": " + err.message;
223
					if (err.response && err.response.data && err.response.data.message) {
224
						message = err.response.data.message;
225
					}
226
					lib.showMessage({
227
						content: message,
228
						targetNode: this.usernameNode,
229
						'class': '.error'
230
					});
231
					this._usernameButton.set('disabled', false);
232
					this._username.set('disabled', false);
233
				}));
234
			} else {
235
				this._usernameButton.set('disabled', false);
236
				this._username.set('disabled', false);
237
			}
238
		},
239
240
		_buildTokenOptions: function(options) {
241
			array.forEach(options, lang.hitch(this, function(obj, idx){
242
				var radioButton = new RadioButton({
243
					name: 'button' + idx,
244
					label: obj.label,
245
					method: obj.id,
246
					checked: idx === 0,
247
					radioButtonGroup: 'token',
248
					_categoryID: 'token'
249
				});
250
				var label = new LabelPane({
251
					'class': 'ucsRadioButtonLabel',
252
					content: radioButton
253
				});
254
				this._tokenOptions.addChild(label);
255
			}));
256
			put(this.tokenNode, '!hide-step');
257
		},
258
259
		_requestToken: function() {
260
			// get selected method for requesting a token
261
			array.some(this._tokenOptions.getChildren(), lang.hitch(this, function(tokenLabel) {
262
				var radioButton = tokenLabel.getChildren()[0];
263
				if (radioButton.checked) {
264
					this.selectedTokenMethod = {
265
						label: radioButton.get('label'),
266
						method: radioButton.get('method')
267
					};
268
				}
269
			}));
270
271
			if (this.selectedTokenMethod) {
272
				this._requestTokenButton.set('disabled', true);
273
				data = json.stringify({
274
					'username': this._username.get('value'),
275
					'method': this.selectedTokenMethod.method
276
				});
277
				xhr.post('passwordreset/send_token', {
278
					handleAs: 'json',
279
					headers: {
280
						'Content-Type': 'application/json',
281
						'Accept-Language': lib.getQuery('lang') || 'en-US'
282
					},
283
					data: data
284
				}).then(lang.hitch(this, function(data) {
285
					lib.showMessage({
286
						content: data.message,
287
						targetNode: this.tokenNode,
288
						'class': '.success'
289
					});
290
					put(this._requestTokenButton.domNode, '.dijitHidden');
291
					put(this.newPasswordNode, '!hide-step');
292
				}), lang.hitch(this, function(err){
293
					var message = err.name + ": " + err.message;
294
					if (err.response && err.response.data && err.response.data.message) {
295
						message = err.response.data.message;
296
					}
297
					lib.showMessage({
298
						content: message,
299
						targetNode: this.tokenNode,
300
						'class': '.error'
301
					});
302
					this._requestTokenButton.set('disabled', false);
303
				}));
304
			}
305
		},
306
307
		_setPassword: function() {
308
			this._setPasswordButton.set('disabled', true);
309
			this._token.set('disabled', true);
310
			this._newPassword.set('disabled', true);
311
			this._verifyPassword.set('disabled', true);
312
313
			var isTokenAndNewPassValid = this._token.isValid() &&
314
				this._newPassword.isValid() &&
315
				this._verifyPassword.isValid();
316
317
			if (isTokenAndNewPassValid) {
318
				data = json.stringify({
319
					'username': this._username.get('value'),
320
					'password': this._verifyPassword.get('value'),
321
					'token' : this._token.get('value')
322
				});
323
				xhr.post('passwordreset/set_password', {
324
					handleAs: 'json',
325
					headers: {
326
						'Content-Type': 'application/json',
327
						'Accept-Language': lib.getQuery('lang') || 'en-US'
328
					},
329
					data: data
330
				}).then(lang.hitch(this, function(data) {
331
					lib._removeMessage();
332
					var callback = function() {
333
						lib.showLastMessage({
334
							content: data.message,
335
							'class': '.success'
336
						});
337
					};
338
					lib.wipeOutNode({
339
						node: dom.byId('form'),
340
						callback: callback
341
					});
342
				}), lang.hitch(this, function(err){
343
					var message = err.name + ": " + err.message;
344
					if (err.response && err.response.data && err.response.data.message) {
345
						message = err.response.data.message;
346
					}
347
					lib.showMessage({
348
						content: message,
349
						targetNode: this.newPasswordNode,
350
						'class': '.error'
351
					});
352
					this._setPasswordButton.set('disabled', false);
353
					this._token.set('disabled', false);
354
					this._newPassword.set('disabled', false);
355
					this._verifyPassword.set('disabled', false);
356
				}));
357
			} else {
358
				this._setPasswordButton.set('disabled', false);
359
				this._token.set('disabled', false);
360
				this._newPassword.set('disabled', false);
361
				this._verifyPassword.set('disabled', false);
362
			}
363
		},
364
365
		_fillContentByUrl: function() {
366
			// checks if the url contains a username and a token
367
			// show and fill the corresponding input fields if true
368
			var token = lib.getQuery('token');
369
			var username = lib.getQuery('username');
370
			if (token && username) {
371
				this._username.set('value', username);
372
				this._token.set('value', token);
373
				put(this.contactNode, '!');
374
				this._getResetMethods();
375
				this._requestTokenButton.set('disabled', true);
376
				put(this.tokenNode, '.dijitHidden');
377
				put(this.newPasswordNode, '!hide-step');
378
			}
379
		},
380
381
		start: function() {
382
			this._createTitle();
383
			this._createContent();
384
		}
385
	};
386
});
(-)a/management/univention-self-service/js/ucs/setcontactinformation.js (-300 lines)
 Lines 1-300    Link Here 
1
/*
2
 * Copyright 2015-2016 Univention GmbH
3
 *
4
 * http://www.univention.de/
5
 *
6
 * All rights reserved.
7
 *
8
 * The source code of this program is made available
9
 * under the terms of the GNU Affero General Public License version 3
10
 * (GNU AGPL V3) as published by the Free Software Foundation.
11
 *
12
 * Binary versions of this program provided by Univention to you as
13
 * well as other copyrighted, protected or trademarked materials like
14
 * Logos, graphics, fonts, specific documentations and configurations,
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
 * GNU Affero General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Affero General Public
25
 * License with the Debian GNU/Linux or Univention distribution in file
26
 * /usr/share/common-licenses/AGPL-3; if not, see
27
 * <http://www.gnu.org/licenses/>.
28
 */
29
/*global define require console window */
30
31
define([
32
	"dojo/_base/lang",
33
	"dojo/_base/array",
34
	"dojo/on",
35
	"dojo/keys",
36
	"dojo/dom",
37
	"dojo/json",
38
	"dojo/request/xhr",
39
	"dijit/form/Button",
40
	"put-selector/put",
41
	"./ContainerWidget",
42
	"./LabelPane",
43
	"./TextBox",
44
	"./RadioButton",
45
	"./lib",
46
	"./i18n!."
47
], function(lang, array, on, keys, dom, json, xhr, Button, put, ContainerWidget, LabelPane, TextBox, RadioButton, lib, _) {
48
49
	return {
50
		selectedTokenMethod: null,
51
		
52
		_createTitle: function() {
53
			var title = _('Contact information for Password reset');
54
			var siteDescription = _('On this page you can set your contact information to reset your password in the future. During the reset process a token is sent to you. Without contact information it is not possible to reset your password.');
55
			document.title = title;
56
			var titleNode = dom.byId('title');
57
			put(titleNode, 'h1', title);
58
			put(titleNode, 'p', siteDescription);
59
			put(titleNode, '!.dijitHidden');
60
		},
61
62
		_createContent: function() {
63
			var contentNode = dom.byId('content');
64
			var formNode = this._getFormNode();
65
			put(formNode, '[id=form].step!dijitHidden');
66
			put(contentNode, formNode);
67
		},
68
69
		_getFormNode: function() {
70
			var formNode = put('div[style="overflow: hidden;"]');
71
72
			// step 1 username and password
73
			this.usernameNode = put(formNode, 'div.step');
74
			put(this.usernameNode, 'p > b', _('Please enter your username and password to display your contact information.'));
75
			var stepContent = put(this.usernameNode, 'div.stepContent');
76
77
			this._username = new TextBox({
78
				label: _('Username'),
79
				'class': 'doubleLabelPane left',
80
				isValid: function() {
81
					return !!this.get('value');
82
				},
83
				required: true
84
			});
85
			this._username.on('keyup', lang.hitch(this, function(evt) {
86
				if (evt.keyCode === keys.ENTER) {
87
					this._getContactInformation();
88
				}
89
			}));
90
			put(stepContent, this._username.label.domNode);
91
			this._username.startup();
92
93
			this._password = new TextBox({
94
				label: _('Password'),
95
				'class': 'doubleLabelPane',
96
				isValid: function() {
97
					return !!this.get('value');
98
				},
99
				required: true,
100
				type: 'password'
101
			});
102
			this._password.on('keyup', lang.hitch(this, function(evt) {
103
				if (evt.keyCode === keys.ENTER) {
104
					this._getContactInformation();
105
				}
106
			}));
107
			put(stepContent, this._password.label.domNode);
108
			this._password.startup();
109
110
			this._showContactInformationButton = new Button({
111
				label: _('Next'),
112
				onClick: lang.hitch(this, '_getContactInformation')
113
			});
114
			put(stepContent, this._showContactInformationButton.domNode);
115
116
			// step 2 show and set contact information
117
			this.contactInformationNode = put(formNode, 'div.step.hide-step');
118
			put(this.contactInformationNode, 'p', _('Feel free to change your contact information. Press "Save" to confirm your changes.'));
119
			stepContent = put(this.contactInformationNode, 'div.stepContent');
120
121
			this._email = new TextBox({
122
				label: _('EMail'),
123
				'class': 'doubleLabelPane left',
124
				id: 'email'
125
			});
126
			this._email.on('keyup', lang.hitch(this, function(evt) {
127
				if (evt.keyCode === keys.ENTER) {
128
					this._setContactInformation();
129
				}
130
			}));
131
			put(stepContent, this._email.label.domNode);
132
133
			this._mobile = new TextBox({
134
				label: _('Mobile'),
135
				'class': 'doubleLabelPane',
136
				id: 'mobile'
137
			});
138
			this._mobile.on('keyup', lang.hitch(this, function(evt) {
139
				if (evt.keyCode === keys.ENTER) {
140
					this._setContactInformation();
141
				}
142
			}));
143
			put(stepContent, this._mobile.label.domNode);
144
145
			this._saveButton = new Button({
146
				label: _('Save'),
147
				onClick: lang.hitch(this, '_setContactInformation')
148
			});
149
			put(stepContent, this._saveButton.domNode);
150
151
			this._cancelButton = new Button({
152
				label: _('Cancel'),
153
				onClick: lang.hitch(this, '_deleteContactInformationNode')
154
			});
155
			put(stepContent, this._cancelButton.domNode);
156
157
			return formNode;
158
		},
159
160
		_getContactInformation: function() {
161
			this._username.set('disabled', true);
162
			this._password.set('disabled', true);
163
			this._showContactInformationButton.set('disabled', true);
164
165
			var validCredentials = this._username.isValid() && this._password.isValid();
166
			if (validCredentials) {
167
				data = json.stringify({
168
					'username': this._username.get('value'),
169
					'password': this._password.get('value')
170
				});
171
				xhr.post('passwordreset/get_contact', {
172
					handleAs: 'json',
173
					headers: {
174
						'Content-Type': 'application/json',
175
						'Accept-Language': lib.getQuery('lang') || 'en-US'
176
					},
177
					data: data
178
				}).then(lang.hitch(this, function(data) {
179
					lib._removeMessage();
180
					put(this._showContactInformationButton.domNode, '.dijitHidden');
181
					this._displayContactInformation(data.result);
182
				}), lang.hitch(this, function(err){
183
					var message = err.name + ": " + err.message;
184
					if (err.response && err.response.data && err.response.data.message) {
185
						message = err.response.data.message;
186
					}
187
					lib.showMessage({
188
						content: message,
189
						targetNode: this.usernameNode,
190
						'class': '.error'
191
					});
192
					this._showContactInformationButton.set('disabled', false);
193
					this._username.set('disabled', false);
194
					this._password.set('disabled', false);
195
				}));
196
			} else {
197
				this._showContactInformationButton.set('disabled', false);
198
				this._username.set('disabled', false);
199
				this._password.set('disabled', false);
200
			}
201
		},
202
203
		_displayContactInformation: function(contactInformation) {
204
			var mappingIdAndInput = {
205
				'email': this._email,
206
				'mobile': this._mobile
207
			};
208
209
			array.forEach(contactInformation, lang.hitch(this, function(contact){
210
				var currentInput = mappingIdAndInput[contact.id];
211
				if (currentInput) {
212
					currentInput.set('value', contact.value);
213
					//currentInput._updateInlineLabelVisibility();
214
				}
215
			}));
216
			put(this.contactInformationNode, '!hide-step');
217
		},
218
219
		_setContactInformation: function() {
220
			this._cancelButton.set('disabled', true);
221
			this._saveButton.set('disabled', true);
222
223
			data = this._getNewContactInformation();
224
			var isValidMail = this._validateMail(data.email);
225
			if (isValidMail) {
226
				xhr.post('passwordreset/set_contact', {
227
						handleAs: 'json',
228
						headers: {
229
							'Content-Type': 'application/json',
230
							'Accept-Language': lib.getQuery('lang') || 'en-US'
231
						},
232
						data: json.stringify(data)
233
					}).then(lang.hitch(this, function(data) {
234
						lib._removeMessage();
235
						var callback = function() {
236
							lib.showLastMessage({
237
								content: data.message,
238
								'class': '.success'
239
							});
240
						};
241
						lib.wipeOutNode({
242
							node: dom.byId('form'),
243
							callback: callback
244
						});
245
					}), lang.hitch(this, function(err){
246
						var message = err.name + ": " + err.message;
247
						if (err.response && err.response.data && err.response.data.message) {
248
							message = err.response.data.message;
249
						}
250
						lib.showMessage({
251
							content: message,
252
							targetNode: this.contactInformationNode,
253
							'class': '.error'
254
						});
255
						this._cancelButton.set('disabled', false);
256
						this._saveButton.set('disabled', false);
257
					}));
258
			} else {
259
				this._cancelButton.set('disabled', false);
260
				this._saveButton.set('disabled', false);
261
			}
262
		},
263
264
		_getNewContactInformation: function() {
265
			var contactInformation = {
266
				'username': this._username.get('value'),
267
				'password': this._password.get('value'),
268
				'email': this._email.get('value'),
269
				'mobile': this._mobile.get('value')
270
			};
271
			return contactInformation;
272
		},
273
274
		_validateMail: function(email) {
275
			var reg = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
276
			var isValid = !email.length || reg.test(email);
277
			if(!isValid) {
278
				lib.showMessage({
279
					content: _('Please enter a valid email address.'),
280
					'class': '.error',
281
					targetNode: this.contactInformationNode
282
				});
283
			}
284
			return isValid;
285
		},
286
287
		_deleteContactInformationNode: function() {
288
			put(this.contactInformationNode, '.hide-step');
289
			put(this._showContactInformationButton.domNode, '!dijitHidden');
290
			this._showContactInformationButton.set('disabled', false);
291
			this._username.reset();
292
			this._password.reset();
293
		},
294
295
		start: function() {
296
			this._createTitle();
297
			this._createContent();
298
		}
299
	};
300
});
(-)a/management/univention-self-service/www/index.html (-5 / +10 lines)
 Lines 4-10    Link Here 
4
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
4
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
5
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
6
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
7
		<title></title>
7
		<title>Password Settings</title>
8
		<link rel="shortcut icon" href="/favicon.ico" />
8
		<link rel="shortcut icon" href="/favicon.ico" />
9
		<link rel="stylesheet" href="js/dijit/themes/dijit.css">
9
		<link rel="stylesheet" href="js/dijit/themes/dijit.css">
10
		<link rel="stylesheet" href="css/bootstrap.css"/>
10
		<link rel="stylesheet" href="css/bootstrap.css"/>
 Lines 16-32    Link Here 
16
		<div id="wrapper">
16
		<div id="wrapper">
17
			<div id="site-header">
17
			<div id="site-header">
18
				<div id="header-top">
18
				<div id="header-top">
19
					<div id="header-left">
19
					<a id="header-left" href="/ucs-overview">
20
					</div>
20
					</a>
21
					<a id="header-middle" href="/ucs-overview"></a>
21
					<div id="header-right">
22
					<div id="header-right">
22
						<div class="dropdown" id="dropDownButton"></div>
23
						<div class="dropdown" id="dropDownButton"></div>
23
					</div>
24
					</div>
24
				</div>
25
				</div>
25
			</div>
26
			</div>
26
			<div class="container">
27
			<div class="container">
27
				<div id="title" class="dijitHidden">
28
				<div id="title">
29
					Password Settings
28
				</div>
30
				</div>
29
				<div id="content">
31
				<div id="navigation"></div>
32
				<div id="content" class="tab-content">
30
					<noscript>
33
					<noscript>
31
						<div>
34
						<div>
32
							<h1 class="no-js">Welcome to Univention Corporate Server</h1>
35
							<h1 class="no-js">Welcome to Univention Corporate Server</h1>
 Lines 39-45    Link Here 
39
						</div>
42
						</div>
40
					</noscript>
43
					</noscript>
41
				</div>
44
				</div>
45
				<div id="server_msg"></div>
42
			</div>
46
			</div>
47
			<div class="footer dijitHidden" id="footer"></div>
43
		</div>
48
		</div>
44
	</body>
49
	</body>
45
</html>
50
</html>

Return to bug 42267