diff --git a/locale/ubl-settings-usergroups.pot b/locale/ubl-settings-usergroups.pot index 1f11d21..06afdf3 100644 --- a/locale/ubl-settings-usergroups.pot +++ b/locale/ubl-settings-usergroups.pot @@ -1058,4 +1058,16 @@ msgstr "" #: source/ubl-strings.h:302 msgid "The login rules are not followed" +msgstr "" + +#: source/ubl-strings.h:302 +msgid "The password does not meet the password policy requirements" +msgstr "" + +#: source/ubl-strings.h:302 +msgid "- Latin characters only\n- Maximum 256 characters" +msgstr "" + +#: source/ubl-strings.h:302 +msgid "- Latin characters only\n- Start with a-zA-Z_ only\n- Use only characters a-zA-Z0-9_-\n- Maximum 32 characters\n- Regexp check [a-zA-Z_][a-zA-Z0-9_-]*" msgstr "" \ No newline at end of file diff --git a/locale/ubl-settings-usergroups_ru.po b/locale/ubl-settings-usergroups_ru.po index f0144e8..6ba7b67 100644 --- a/locale/ubl-settings-usergroups_ru.po +++ b/locale/ubl-settings-usergroups_ru.po @@ -1152,3 +1152,15 @@ msgstr "Правила составления логина не соблюден #~ msgid "main group will be set to default group" #~ msgstr "получит(-ат) основную группу по умолчанию" + +#: source/ubl-strings.h:302 +msgid "The password does not meet the password policy requirements" +msgstr "Пароль не соответствует требованиям политики паролей" + +#: source/ubl-strings.h:302 +msgid "- Latin characters only\n- Maximum 256 characters" +msgstr "- Только латинские символы.\n- Максимум 256 символов." + +#: source/ubl-strings.h:302 +msgid "- Latin characters only\n- Start with a-zA-Z_ only\n- Use only characters a-zA-Z0-9_-\n- Maximum 32 characters\n- Regexp check [a-zA-Z_][a-zA-Z0-9_-]*" +msgstr "- Только латинские символы\n- Начало только c a-zA-Z_\n- Использовать только символы a-zA-Z0-9_-\n- Максимум 32 символа\n- Проверка regexp [a-zA-Z_][a-zA-Z0-9_-]*" \ No newline at end of file diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 1758e4b..b9894e3 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -13,6 +13,11 @@ include_directories(${VTE291_INCLUDE_DIRS}) link_directories(${VTE291_LIBRARY_DIRS}) add_definitions(${VTE291_CFLAGS_OTHER}) +pkg_check_modules(PWQ REQUIRED pwquality) +include_directories(${PWQ_INCLUDE_DIRS}) +link_directories(${PWQ_LIBRARY_DIRS}) +add_definitions(${PWQ_CFLAGS_OTHER}) + find_library(WEBKIT_LIBRARIES_FOUND webkit2gtk-4.0 webkit2gtk-web-extension-4.0) if(WEBKIT_LIBRARIES_FOUND) @@ -95,6 +100,7 @@ set(SOURCE_FILES set(LIBRARIES ${GTK_LIBRARIES} ${VTE291_LIBRARIES} + ${PWQ_LIBRARIES} ublsettings ublsettings-gtk3 ublsettingsui-gtk3 diff --git a/source/ubl-settings-usergroups-password.c b/source/ubl-settings-usergroups-password.c index f922fc0..ce1bfaa 100644 --- a/source/ubl-settings-usergroups-password.c +++ b/source/ubl-settings-usergroups-password.c @@ -63,7 +63,7 @@ void on_password_accept(GtkWidget *self, dictionary *dict){ ubl_settings_usergroups_password_window *window = yon_dictionary_get_data(dict->first,ubl_settings_usergroups_password_window*); GtkEntry *entry = yon_dictionary_get_data(dict->first->next,GtkEntry*); char *password = (char*)gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry)); - char *password_check = (char*)gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry)); + char *password_check = (char*)gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry)); if (yon_char_is_empty(password)){ char *pasted_hash = (char*)gtk_entry_get_text(GTK_ENTRY(window->PasswordHashEntry)); if (!yon_char_is_empty(pasted_hash)){ @@ -95,10 +95,39 @@ void on_password_accept(GtkWidget *self, dictionary *dict){ yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),PASSWORD_MISMATCH_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); return; } + pwquality_settings_t *settings = pwquality_default_settings(); + int password_strength = pwquality_check(settings,password,NULL,NULL,NULL); + if (password_strength<30){ + yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),WEAK_PASSWORD_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); + return; + } + } on_subwindow_close(self); } +void on_password_changed(GtkWidget *, ubl_settings_usergroups_password_window *window){ + pwquality_settings_t *settings = pwquality_default_settings(); + const char *new_password = gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry)); + int password_strength = pwquality_check(settings,new_password,NULL,NULL,NULL); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(window->PasswordStrengthProgress),(gdouble)password_strength/100); + if (password_strength<30){ + gtk_style_context_add_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"redBox"); + gtk_style_context_remove_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"greenBox"); + gtk_style_context_remove_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"yellowBox"); + } else if (password_strength<60) { + gtk_style_context_add_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"yellowBox"); + gtk_style_context_remove_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"redBox"); + gtk_style_context_remove_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"greenBox"); + + } else { + gtk_style_context_add_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"greenBox"); + gtk_style_context_remove_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"redBox"); + gtk_style_context_remove_class(gtk_widget_get_style_context(window->PasswordStrengthProgress),"yellowBox"); + } + +} + void on_password_hash_sensitiveness(GtkWidget *,ubl_settings_usergroups_password_window *window){ if (!yon_char_is_empty(gtk_entry_get_text(GTK_ENTRY(window->PasswordEntry)))||!yon_char_is_empty(gtk_entry_get_text(GTK_ENTRY(window->RepeatPasswordEntry)))){ gtk_widget_set_sensitive(window->HashBox,0); @@ -112,6 +141,43 @@ void on_password_hash_sensitiveness(GtkWidget *,ubl_settings_usergroups_password } } +gboolean on_password_focus_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window){ + gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + gtk_popover_popup(GTK_POPOVER(window->PasswordTooltipPopover)); + gtk_widget_grab_focus(self); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + return GDK_EVENT_PROPAGATE; +} + +gboolean on_password_focus_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window){ + gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT); + gtk_popover_popdown(GTK_POPOVER(window->PasswordTooltipPopover)); + return GDK_EVENT_PROPAGATE; +} +gboolean on_password_tooltip_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window){ + gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + gtk_popover_popup(GTK_POPOVER(window->PasswordTooltipPopover)); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + return GDK_EVENT_PROPAGATE; +} + +gboolean on_password_tooltip_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window){ + if (gtk_widget_has_focus(window->PasswordEntry)) return GDK_EVENT_PROPAGATE; + gtk_popover_set_relative_to(GTK_POPOVER(window->PasswordTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->PasswordTooltipPopover),GTK_POS_RIGHT); + gtk_popover_popdown(GTK_POPOVER(window->PasswordTooltipPopover)); + return GDK_EVENT_PROPAGATE; +} + ubl_settings_usergroups_password_window *yon_ubl_settings_usergroups_password_new(){ ubl_settings_usergroups_password_window *window = malloc(sizeof(ubl_settings_usergroups_password_window)); GtkBuilder *builder = gtk_builder_new_from_resource(glade_path_ubl_settings_usergroups_password); @@ -123,6 +189,9 @@ ubl_settings_usergroups_password_window *yon_ubl_settings_usergroups_password_ne window->HashBox=yon_gtk_builder_get_widget(builder,"HashBox"); window->PasswordBox=yon_gtk_builder_get_widget(builder,"PasswordBox"); window->NoEncriptionCheck=yon_gtk_builder_get_widget(builder,"NoEncriptionCheck"); + window->PasswordStrengthProgress=yon_gtk_builder_get_widget(builder,"PasswordStrengthProgress"); + window->PasswordTooltipPopover=yon_gtk_builder_get_widget(builder,"PasswordTooltipPopover"); + window->PassowordTooltipLabel=yon_gtk_builder_get_widget(builder,"PassowordTooltipLabel"); window->UserCancelButton=yon_gtk_builder_get_widget(builder,"UserCancelButton"); window->UserOkButton=yon_gtk_builder_get_widget(builder,"UserOkButton"); @@ -130,13 +199,19 @@ ubl_settings_usergroups_password_window *yon_ubl_settings_usergroups_password_ne yon_window_config_custom_window_setup(GTK_WINDOW(window->CreateGroupWindow),"PasswordWindow"); g_signal_connect(G_OBJECT(window->UserCancelButton),"clicked",G_CALLBACK(on_subwindow_close),NULL); g_signal_connect(G_OBJECT(window->PasswordEntry),"icon-press",G_CALLBACK(on_password_show_hide),NULL); + g_signal_connect(G_OBJECT(window->PasswordEntry),"changed",G_CALLBACK(on_password_changed),window); g_signal_connect(G_OBJECT(window->PasswordEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window); g_signal_connect(G_OBJECT(window->RepeatPasswordEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window); g_signal_connect(G_OBJECT(window->PasswordHashEntry),"changed",G_CALLBACK(on_password_hash_sensitiveness),window); g_signal_connect(G_OBJECT(window->RepeatPasswordEntry),"icon-press",G_CALLBACK(on_password_show_hide),NULL); g_signal_connect(G_OBJECT(window->PasswordHashEntry),"icon-press",G_CALLBACK(on_password_show_hide),NULL); + g_signal_connect(G_OBJECT(window->PasswordEntry),"focus-in-event",G_CALLBACK(on_password_focus_event),window); + g_signal_connect(G_OBJECT(window->PasswordEntry),"focus-out-event",G_CALLBACK(on_password_focus_out_event),window); + g_signal_connect(G_OBJECT(window->PasswordEntry),"enter-notify-event",G_CALLBACK(on_password_tooltip_event),window); + g_signal_connect(G_OBJECT(window->PasswordEntry),"leave-notify-event",G_CALLBACK(on_password_tooltip_out_event),window); gtk_window_set_title(GTK_WINDOW(window->CreateGroupWindow),PASSWORD_TITLE_LABEL); + return window; } diff --git a/source/ubl-settings-usergroups-user.c b/source/ubl-settings-usergroups-user.c index f0f49e7..4364475 100644 --- a/source/ubl-settings-usergroups-user.c +++ b/source/ubl-settings-usergroups-user.c @@ -1,5 +1,42 @@ #include "ubl-settings-usergroups.h" +gboolean on_login_focus_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window){ + gtk_popover_set_relative_to(GTK_POPOVER(window->LoginTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->LoginTooltipPopover),GTK_POS_RIGHT); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + gtk_popover_popup(GTK_POPOVER(window->LoginTooltipPopover)); + gtk_widget_grab_focus(self); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + return GDK_EVENT_PROPAGATE; +} + +gboolean on_login_focus_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window){ + gtk_popover_set_relative_to(GTK_POPOVER(window->LoginTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->LoginTooltipPopover),GTK_POS_RIGHT); + gtk_popover_popdown(GTK_POPOVER(window->LoginTooltipPopover)); + return GDK_EVENT_PROPAGATE; +} +gboolean on_login_tooltip_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window){ + gtk_popover_set_relative_to(GTK_POPOVER(window->LoginTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->LoginTooltipPopover),GTK_POS_RIGHT); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_block_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + gtk_popover_popup(GTK_POPOVER(window->LoginTooltipPopover)); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_out_event),window); + g_signal_handlers_unblock_by_func(G_OBJECT(self),G_CALLBACK(on_password_focus_event),window); + return GDK_EVENT_PROPAGATE; +} + +gboolean on_login_tooltip_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window){ + if (gtk_widget_has_focus(window->userLoginEntry)) return GDK_EVENT_PROPAGATE; + gtk_popover_set_relative_to(GTK_POPOVER(window->LoginTooltipPopover),self); + gtk_popover_set_position(GTK_POPOVER(window->LoginTooltipPopover),GTK_POS_RIGHT); + gtk_popover_popdown(GTK_POPOVER(window->LoginTooltipPopover)); + return GDK_EVENT_PROPAGATE; +} + char *yon_user_get_system_groups(char *target_login){ char *groups_string = NULL; groups_string=""; @@ -269,6 +306,7 @@ ubl_settings_usergroups_user_window *yon_ubl_settings_usergroups_user_new(){ window->UsershadowShutdownCheck=yon_gtk_builder_get_widget(builder,"UsershadowShutdownCheck"); window->userTitleNameLabel=yon_gtk_builder_get_widget(builder,"userTitleNameLabel"); window->MainNotebook=yon_gtk_builder_get_widget(builder,"MainNotebook"); + window->LoginTooltipPopover=yon_gtk_builder_get_widget(builder,"LoginTooltipPopover"); window->expiration_unix=NULL; window->last_uid=NULL; yon_gtk_entry_block_symbols(GTK_ENTRY(window->userUserNameEntry),"'\":\n"); @@ -305,6 +343,10 @@ ubl_settings_usergroups_user_window *yon_ubl_settings_usergroups_user_new(){ yon_dictionary_add_or_create_if_exists_with_data(entry_dict,"combo",window->userPasswordCombo); yon_dictionary_add_or_create_if_exists_with_data(entry_dict,"entry",window->userPasswordEntry); // char *password = yon_config_get_by_key(USERADD((char*)gtk_entry_get_text(GTK_ENTRY(window->userLoginEntry)))); + g_signal_connect(G_OBJECT(window->userLoginEntry),"focus-in-event",G_CALLBACK(on_login_focus_event),window); + g_signal_connect(G_OBJECT(window->userLoginEntry),"focus-out-event",G_CALLBACK(on_login_focus_out_event),window); + g_signal_connect(G_OBJECT(window->userLoginEntry),"enter-notify-event",G_CALLBACK(on_login_tooltip_event),window); + g_signal_connect(G_OBJECT(window->userLoginEntry),"leave-notify-event",G_CALLBACK(on_login_tooltip_out_event),window); g_signal_connect(G_OBJECT(window->UserCancelButton),"clicked",G_CALLBACK(on_subwindow_close),NULL); g_signal_connect(G_OBJECT(window->userUIDAutoCheck),"toggled",G_CALLBACK(yon_gtk_widget_set_sensitive_from_toggle_button_inversed),window->userUIDEntry); g_signal_connect(G_OBJECT(window->userHomeButton),"clicked",G_CALLBACK(on_filechooser_open),window->userHomeEntry); @@ -485,12 +527,7 @@ void on_user_save(GtkWidget *self, dictionary *dict){ return; } - if (login[0]>'0'&&login[0]<'9'&&!do_not_check_actve){ - yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),USER_BEGINS_WITH_DIGIT_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); - yon_ubl_status_highlight_incorrect(window->userLoginEntry); - return; - } - if ((strstr(login," ")||strstr(login,"\'")||strstr(login,"\"")||strstr(login,"\n")||strstr(login,"`"))&&!do_not_check_actve){ + if (!g_regex_match_simple("[a-zA-Z_][a-zA-Z0-9_-]*",login,0,0)&&!do_not_check_actve){ yon_ubl_status_box_spawn(GTK_CONTAINER(window->StatusBox),INVALID_LOGIN_LABEL,5,BACKGROUND_IMAGE_FAIL_TYPE); yon_ubl_status_highlight_incorrect(window->userLoginEntry); return; diff --git a/source/ubl-settings-usergroups.h b/source/ubl-settings-usergroups.h index c7e0a4e..6cb8b55 100644 --- a/source/ubl-settings-usergroups.h +++ b/source/ubl-settings-usergroups.h @@ -18,6 +18,7 @@ #include #endif #include "ubl-strings.h" +#include "pwquality.h" #define WIKI_LINK "https://wiki.ublinux.ru/software/programs_and_utilities/all/ubl-settings-usergroups" @@ -370,6 +371,9 @@ typedef struct{ GtkWidget *HashBox; GtkWidget *PasswordBox; GtkWidget *NoEncriptionCheck; + GtkWidget *PasswordStrengthProgress; + GtkWidget *PasswordTooltipPopover; + GtkWidget *PassowordTooltipLabel; } ubl_settings_usergroups_password_window; typedef struct { @@ -438,6 +442,7 @@ typedef struct{ GtkWidget *userTitleNameLabel; GtkWidget *userSyncSAMBAPasswordCheck; GtkWidget *MainNotebook; + GtkWidget *LoginTooltipPopover; char *expiration_unix; @@ -638,4 +643,13 @@ int yon_config_check_valid(); void on_home_changed(GtkWidget *self,ubl_settings_usergroups_user_window *window); gboolean yon_user_set_locales(GtkWidget *target); void *yon_load_languages(void *target); +void on_password_changed(GtkWidget *, ubl_settings_usergroups_password_window *window); +gboolean on_password_focus_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window); +gboolean on_password_focus_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window); +gboolean on_password_tooltip_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window); +gboolean on_password_tooltip_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_password_window *window); +gboolean on_login_focus_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window); +gboolean on_login_focus_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window); +gboolean on_login_tooltip_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window); +gboolean on_login_tooltip_out_event(GtkWidget *self, GdkEvent *, ubl_settings_usergroups_user_window *window); #endif \ No newline at end of file diff --git a/source/ubl-strings.h b/source/ubl-strings.h index ee2fbfe..948c679 100644 --- a/source/ubl-strings.h +++ b/source/ubl-strings.h @@ -297,4 +297,7 @@ #define SYSTEM_LANGUAGE_LABEL _("System language:") #define REGIONAL_SETTINGS_LABEL _("Regional settings") #define SYSTEM_LABEL _("System") -#define INVALID_LOGIN_LABEL _("The login rules are not followed") \ No newline at end of file +#define INVALID_LOGIN_LABEL _("The login rules are not followed") +#define WEAK_PASSWORD_LABEL _("The password does not meet the password policy requirements") +#define PASSWORD_LIMITATIONS_TOOLTIP_LABEL _("- Latin characters only\n- Maximum 256 characters") +#define LOGIN_LIMITATIONS_TOOLTIP_LABEL _("- Latin characters only\n- Start with a-zA-Z_ only\n- Use only characters a-zA-Z0-9_-\n- Maximum 32 characters\n- Regexp check [a-zA-Z_][a-zA-Z0-9_-]*") \ No newline at end of file diff --git a/ubl-settings-usergroups-password.glade b/ubl-settings-usergroups-password.glade index 50bce69..39a212f 100644 --- a/ubl-settings-usergroups-password.glade +++ b/ubl-settings-usergroups-password.glade @@ -3,6 +3,26 @@ + + False + right + False + none + + + True + False + 5 + 5 + 5 + 5 + - Latin characters only +- Maximum 256 characters + 0 + 0 + + + True False @@ -77,6 +97,7 @@ True True + 256 False * True @@ -139,6 +160,43 @@ 1 + + + True + False + 5 + + + True + False + + + + + + False + True + 0 + + + + + True + False + + + True + True + 1 + + + + + False + True + 2 + + Do not encrypt password @@ -150,7 +208,7 @@ False True - 2 + 3 @@ -161,7 +219,7 @@ False True - 3 + 4 @@ -281,8 +339,9 @@ - + + diff --git a/ubl-settings-usergroups-user.glade b/ubl-settings-usergroups-user.glade index 6c829cd..edb5961 100644 --- a/ubl-settings-usergroups-user.glade +++ b/ubl-settings-usergroups-user.glade @@ -3,6 +3,31 @@ + + False + right + False + none + + + True + False + 5 + 5 + 5 + 5 + 5 + 5 + - Latin characters only +- Start with a-zA-Z_ only +- Use only characters a-zA-Z0-9_- +- Maximum 32 characters +- Regexp check [a-zA-Z_][a-zA-Z0-9_-]* + 0 + 0 + + + 1e+21 @@ -312,6 +337,7 @@ True True + 32 User name diff --git a/ubl-settings-usergroups.css b/ubl-settings-usergroups.css index 47d2ef3..c717974 100644 --- a/ubl-settings-usergroups.css +++ b/ubl-settings-usergroups.css @@ -118,7 +118,6 @@ background:transparent; border-color: #ea9999; border-style:solid; } - .chosenOutline{ transition: 0ms; border-width: 1px; @@ -126,6 +125,18 @@ background:transparent; border-style:solid; } +.greenBox > trough > progress{ + background-color: #99eaab; +} + +.redBox > trough > progress{ + background-color: #ea9999; +} + +.yellowBox > trough > progress{ + background-color: #f3f0ac; +} + .debugborders *{ border-width: 2px; border-color: #000000;