ukui-biometric-auth/0000775000175000017500000000000015167732644013406 5ustar fengfengukui-biometric-auth/bioauth-bin/0000775000175000017500000000000015167732644015607 5ustar fengfengukui-biometric-auth/bioauth-bin/src/0000775000175000017500000000000015167732644016376 5ustar fengfengukui-biometric-auth/bioauth-bin/src/keywatcher.cpp0000664000175000017500000000411015167732630021237 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "keywatcher.h" #include KeyWatcher::KeyWatcher(QObject *parent) : QThread(parent) { } void KeyWatcher::run() { // 修改终端属性,保证按键被立即接收 struct termios current; tcgetattr(0, &save); current = save; current.c_lflag &= ~ICANON; current.c_lflag &= ~ECHO; current.c_cc[VMIN] = 1; current.c_cc[VTIME] = 0; tcsetattr(0, TCSANOW, ¤t); bool isInputEnd = false; while(!isInterruptionRequested()){ fd_set readfds; FD_ZERO(&readfds); FD_SET(0, &readfds); char ch; switch(select(32, &readfds, NULL, NULL, NULL)){ case 0: // printf("select time out\n"); break; case -1: // printf("select error\n"); break; default: // 'q' | 'Q' or Esc if((ch = getchar()) == 'q' || ch == 'Q' || ch == 27 || ch == EOF){ tcsetattr(0, TCSANOW, &save); emit exit(); if (ch == EOF) { isInputEnd = true; break; } } } if (isInputEnd) { break; } } tcsetattr(0, TCSANOW, &save); // 恢复原来的终端属性,以免干扰shall和之后的程序运行 } void KeyWatcher::stop() { tcsetattr(0, TCSANOW, &save); requestInterruption(); terminate(); wait(); } ukui-biometric-auth/bioauth-bin/src/main.cpp0000664000175000017500000003144615167732644020036 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ //#include "mainwindow.h" #include #include #include #include #include #include #include #include "generic.h" #include "keywatcher.h" #include "bioauth.h" #include "biodevices.h" #define START_COLOR "\033[1;31m" #define RESULT_COLOR "\033[1;31m" #define PROMPT_COLOR "\033[33m" #define NOTIFY_COLOR //"\033[37m" #define QUESTION_COLOR //"\033[1;37m" #define RESET_COLOR "\033[0m" bool enableDebug; QString logPrefix; BioAuth bioAuth; enum MsgType { START, PROMPT, NOTIFY, QUESTION, RESULT }; enum _Option { OPTION_TRY_AGAIN, OPTION_SELECT_DEVICE, OPTION_CANCEL, OPTION_UNDEFINED }; typedef enum _Option Option; static QString lastMessage; void showMessage(const QString &message, int type) { // filter out the same message if(message == lastMessage) return; lastMessage = message; char *text = message.toLocal8Bit().data(); switch(type) { case START: fprintf(stdout, START_COLOR "=== %s ===\n", text); break; case PROMPT: fprintf(stdout, PROMPT_COLOR "%s\n", text); break; case NOTIFY: fprintf(stdout, NOTIFY_COLOR "%s\n", text); break; case QUESTION: fprintf(stdout, QUESTION_COLOR "%s", text); break; case RESULT: fprintf(stdout, RESULT_COLOR "=== %s ===\n", text); break; default: fprintf(stdout, "%s\n", text); break; } fprintf(stdout, RESET_COLOR); } static bool isQuickInput() { fd_set readfds; FD_ZERO(&readfds); FD_SET(0, &readfds); // stdin struct timeval timeout = {0, 10*1000}; switch (select(32, &readfds, NULL, NULL, &timeout)) { case 0: // time out break; case -1: // error break; default: return true; } return false; } QString inputPinCode() { struct termios current; struct termios save; tcgetattr(0, &save); current = save; // current.c_lflag &= ~ICANON; current.c_lflag &= ~ECHO; current.c_cc[VMIN] = 0; current.c_cc[VTIME] = 0; tcsetattr(0, TCSANOW, ¤t); QString password = ""; showMessage(QObject::tr("Enter the ukey password"), QUESTION); char line[1024] = {0}; fgets(line, sizeof(line), stdin); //scanf("%s",&line); showMessage("\n", QUESTION); line[1023] = '\0'; if(line[strnlen(line,1024) - 1] == '\n') line[strnlen(line,1024) - 1] = '\0'; QString str(line); tcsetattr(0, TCSANOW, &save); // 恢复原来的终端属性,以免干扰shall和之后的程序运行 return line; } Option showOption(bool showSelectDevices) { QStringList optionList; QString message; optionList << QObject::tr("Try it again"); if(showSelectDevices) optionList << QObject::tr("Use other Devices"); optionList << QObject::tr("Cancel"); for(int i = 0; i < optionList.size(); i++){ message = QString(" %1. %2\n") .arg(QString::number(i+1)) .arg(optionList.at(i)); showMessage(message, QUESTION); } message = QString("%1 (1-%2):") .arg(QObject::tr("Choose the option")) .arg(QString::number(optionList.size())); showMessage(message, QUESTION); char line[1024]; fgets(line, sizeof(line), stdin); if(line[strnlen(line,1024) - 1] == '\n') line[strnlen(line,1024) - 1] = '\0'; if(!strcmp(line, "1")) return OPTION_TRY_AGAIN; else if(!strcmp(line, "2")) { if(showSelectDevices) return OPTION_SELECT_DEVICE; else return OPTION_CANCEL; } else if(showSelectDevices && !strcmp(line, "3")) return OPTION_CANCEL; else { showMessage(QObject::tr("Invaild response \"") + line + "\"" + "," + QObject::tr("authentication will be canceld") , NOTIFY); showMessage(QObject::tr("AUTHENTICATION CANCELED"), START); exit(BIO_FAILED); } return OPTION_UNDEFINED; } DeviceInfo showDevices(const QMap> &devicesMap) { int count = 0; QString message; showMessage(QObject::tr("=== BIOMETRIC DEVICES ==="), PROMPT); for(auto type : devicesMap.keys()) { for(auto deviceInfo : devicesMap[type]) { message = QString(" %1. [%2] %3") .arg(QString::number(++count)) .arg(BioDevices::bioTypeToString_tr(type)) .arg(deviceInfo.device_shortname); showMessage(message, NOTIFY); } } message = QString("%1 (1-%2):") .arg(QObject::tr("Choose the device")) .arg(QString::number(count)); showMessage(message, QUESTION); char line[1024]; fgets(line, sizeof(line), stdin); if(line[strnlen(line,1024) - 1] == '\n') line[strnlen(line,1024) - 1] = '\0'; for(auto ch : QString(line)) { if(!ch.isDigit()){ showMessage(QObject::tr("Invaild response \"") + line + "\"" + "," +QObject::tr("authentication will be canceld") , NOTIFY); showMessage(QObject::tr("AUTHENTICATION CANCELED"), START); exit(BIO_FAILED); } } int deviceIndex = QString(line).toInt(); if(deviceIndex > count) { showMessage(QObject::tr("Invaild response \"") + line + "\"" + "," + QObject::tr("authentication will be canceld"), NOTIFY); showMessage(QObject::tr("AUTHENTICATION CANCELED"), START); exit(BIO_FAILED); } int i = 0; for(auto type : devicesMap.keys()) { int size = devicesMap[type].size(); if(i + size >= deviceIndex) { return devicesMap[type][deviceIndex - i - 1]; } i += size; } return DeviceInfo(); } static void signal_handler(int signo) { if (signo == SIGHUP) { bioAuth.stopAuth(); } } int main(int argc, char *argv[]) { QCoreApplication::setSetuidAllowed(true); QCoreApplication a(argc, argv); QString locale = QLocale::system().name(); QTranslator translator, translator_bin; QString qmfile = QString("%1/i18n_qm/%2.qm").arg(GET_STR(UKUI_BIOMETRIC)).arg(locale); QString qmfile_bin = QString("%1/i18n_qm/bioauth-bin/%2.qm").arg(GET_STR(UKUI_BIOMETRIC)).arg(locale); qDebug() << "load translation file " << qmfile << qmfile_bin; translator.load(qmfile); translator_bin.load((qmfile_bin)); a.installTranslator(&translator); a.installTranslator(&translator_bin); QCommandLineParser parser; QCommandLineOption serviceOption({"s", "service"}, QObject::tr("Sevice Name"), "service", ""); QCommandLineOption displayOption({"x", "display"}, QObject::tr("DISPLAY env"), "display", ":0"); QCommandLineOption usernameOption({"u", "user"}, QObject::tr("User"), "user", ""); QCommandLineOption debugOption({"d", "debug"}, QObject::tr("Display debug information")); QCommandLineOption deviceOption({"e", "device"}, QObject::tr("Device short name"), ""); parser.addOptions({serviceOption, displayOption, usernameOption, debugOption, deviceOption}); parser.process(a); if(parser.isSet(debugOption)) enableDebug = true; else enableDebug = false; logPrefix = "[pam-diaglog]:"; qInstallMessageHandler(outputMessage); QString serverName = parser.value(serviceOption); if (serverName == "sudo" && isQuickInput()) { exit(BIO_ERROR); } QString userName = parser.value(usernameOption); if(userName.isEmpty()) exit(BIO_ERROR); qDebug() << "authentication user: " << userName; uid_t uid; struct passwd *pwd = getpwnam(userName.toLocal8Bit().data()); if(pwd) uid = pwd->pw_uid; else exit(BIO_ERROR); BioDevices bioDevices(true); bioDevices.setUId(uid); int maxFailedTimes = bioDevices.getFailedTimes(); DeviceInfoPtr deviceInfo = bioDevices.getDefaultDevice(uid); bool isHiddenSwitchButton = bioDevices.GetHiddenSwitchButton(); if(!deviceInfo){ // 只检查默认设备,不再使用第一个设备 exit(BIO_ERROR); } if(bioDevices.getFeatureCount(uid)<1) exit(BIO_ERROR); if(deviceInfo->biotype == 6){ showMessage(QObject::tr("UKEY AUTHENTICATION"), START); }else{ showMessage(QObject::tr("BIOMETRIC AUTHENTICATION"), START); if(!isHiddenSwitchButton) showMessage(QObject::tr("Press Q or Esc to cancel"), PROMPT); } bioAuth.setUid(uid); bioAuth.setDevice(deviceInfo); KeyWatcher watcher; QMap m_failedTimes; QObject::connect(&bioAuth, &BioAuth::notify, &a, [&](const QString &msg){ showMessage(msg, NOTIFY); }); QObject::connect(&bioAuth, &BioAuth::authComplete, &a, [&](uid_t uid_, int result, int retErrNo){ Q_UNUSED(retErrNo); watcher.stop(); bool isBioEnable = bioDevices.GetBioAuthEnable(uid_); bool isUkeyDevice = false; if(deviceInfo && deviceInfo->biotype == 6){ isUkeyDevice = true; } if(!isBioEnable && !isUkeyDevice){ showMessage(QObject::tr("BIOMETRIC AUTHENTICATION IS CLOSED"), RESULT); exit(BIO_IGNORE); } if(result && uid == uid_) { showMessage(QObject::tr("AUTHENTICATION SUCCESS"), RESULT); exit(BIO_SUCCESS); } else { showMessage(QObject::tr("AUTHENTICATION FAILED"), RESULT); DeviceInfoPtr curDeviceInfo = bioAuth.getDevice(); if (m_failedTimes.contains(deviceInfo->device_id)) { m_failedTimes[curDeviceInfo->device_id] = m_failedTimes[curDeviceInfo->device_id] + 1; } else { m_failedTimes[curDeviceInfo->device_id] = 1; } if(m_failedTimes[curDeviceInfo->device_id]biotype)).arg(maxFailedTimes-m_failedTimes[deviceInfo->device_id]),RESULT); }else{ showMessage(QObject::tr("Unable to verify %1, please enter password.").arg(bioDevices.bioTypeToString_tr(curDeviceInfo->biotype)),RESULT); exit(BIO_IGNORE); } Option option = showOption(bioDevices.getAllDevices().count() > 1); switch(option) { case OPTION_TRY_AGAIN: if(deviceInfo->biotype == 6){ QString code = inputPinCode(); bioAuth.SetExtraInfo("pincode",code); } bioAuth.startAuth(); watcher.start(); break; case OPTION_SELECT_DEVICE: { deviceInfo = std::make_shared(); *deviceInfo = showDevices(bioDevices.getAllDevices()); bioAuth.setDevice(deviceInfo); if(deviceInfo->biotype == 6){ QString code = inputPinCode(); bioAuth.SetExtraInfo("pincode",code); } bioAuth.startAuth(); watcher.start(); break; } case OPTION_CANCEL: if(isHiddenSwitchButton) { exit(BIO_ERROR); }else{ if(deviceInfo->biotype == 6){ showMessage(QObject::tr("AUTHENTICATION END"), START); }else{ showMessage(QObject::tr("BIOMETRIC AUTHENTICATION END"), START); } exit(BIO_IGNORE); break; } default: break; } } }); if(deviceInfo->biotype == 6){ QString code = inputPinCode(); bioAuth.SetExtraInfo("pincode",code); } bioAuth.startAuth(); if (!isHiddenSwitchButton) { QObject::connect(&watcher, &KeyWatcher::exit, &a, [&]{ showMessage(QObject::tr("AUTHENTICATION CANCELED"), START); bioAuth.stopAuth(); exit(BIO_IGNORE); }); } watcher.start(); signal(SIGHUP, signal_handler); return a.exec(); } ukui-biometric-auth/bioauth-bin/src/keywatcher.h0000664000175000017500000000176215167732630020716 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef KEYWATCHER_H #define KEYWATCHER_H #include #include class KeyWatcher : public QThread { Q_OBJECT public: explicit KeyWatcher(QObject *parent = nullptr); void run() override; void stop(); signals: void exit(); private: struct termios save; }; #endif // KEYWATCHER_H ukui-biometric-auth/bioauth-bin/CMakeLists.txt0000664000175000017500000000222315167732644020346 0ustar fengfengproject(bioauth-bin) set(CMAKE_AUTOMOC ON) # 定义源文件 set(bin_SRCS src/main.cpp src/keywatcher.cpp ../common/generic.cpp ) # 根据Qt版本设置包含目录和链接库 if(QT_VERSION_MAJOR EQUAL 6) include_directories( ../common ../bioauth/include ${Qt6Core_INCLUDE_DIRS} ${Qt6DBus_INCLUDE_DIRS} ) add_executable(bioauth ${bin_SRCS}) target_link_libraries(bioauth Qt6::Core BioAuth) else() include_directories( ../common ../bioauth/include ${Qt5Core_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS} ) add_executable(bioauth ${bin_SRCS}) target_link_libraries(bioauth Qt5::Core BioAuth) endif() install(TARGETS bioauth DESTINATION bin) file(GLOB ts_files i18n_ts/*.ts) # 根据Qt版本使用相应的翻译函数 if(QT_VERSION_MAJOR EQUAL 6) qt6_add_translation(qm_files ${ts_files}) else() qt5_add_translation(qm_files ${ts_files}) endif() add_custom_target(bioauth-bin_i18n DEPENDS ${qm_files} SOURCES ${ts_files}) add_dependencies(bioauth bioauth-bin_i18n) install(FILES ${qm_files} DESTINATION ${UKUI_BIOMETRIC_DIR}/i18n_qm/bioauth-bin) ukui-biometric-auth/bioauth-bin/i18n_ts/0000775000175000017500000000000015167732644017074 5ustar fengfengukui-biometric-auth/bioauth-bin/i18n_ts/ru.ts0000664000175000017500000001206215167732644020073 0ustar fengfeng BioDevices FingerPrint FingerPrint FingerVein FingerVein Iris Ирис Face Лицо VoicePrint Voiceprint QObject Try it again Попробуйте снова Use other Devices Использовать другие устройства Cancel Отмена Choose the option Выберите вариант Invaild response " Invaild response \ " AUTHENTICATION CANCELED АВТОРИЗАЦИЯ ОТМЕНА === BIOMETRIC DEVICES === === БИОМЕТРИЧЕСКИЕ УСТРОЙСТВА === Choose the device Выберите устройство Sevice Name Имя ячейки DISPLAY env DISPLAY env User пользователь Display debug information Отображать отладочную информацию Device short name Краткое название устройства BIOMETRIC AUTHENTICATION БИОМЕТРИЧЕСКАЯ АУТЕНТИФИКАЦИЯ Press Q or Esc to cancel Нажмите Q или Esc, чтобы отменить AUTHENTICATION SUCCESS УСПЕХ АУТЕНТИФИКАЦИИ AUTHENTICATION FAILED АВТОРИЗАЦИЯ НЕИСПРАВНО BIOMETRIC AUTHENTICATION END КОНТРОЛЬ БИОМЕТРИЧЕСКОЙ АВТОРИЗАЦИИ authentication will be canceld Failed to verify %1, you still have %2 verification opportunities Unable to verify %1, please enter password. Enter the ukey password UKEY AUTHENTICATION BIOMETRIC AUTHENTICATION IS CLOSED AUTHENTICATION END ukui-biometric-auth/bioauth-bin/i18n_ts/de.ts0000664000175000017500000002547215167732644020046 0ustar fengfeng BioAuthWidget More 更多 Retry wiederholen Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password Passwort Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 Es gibt zu viele fehlgeschlagene Versuche, bitte geben Sie Ihr Passwort ein. %1 authentication failure,there are still %2 remaining opportunities %1 Authentifizierung fehlgeschlagen und es sind noch %2 verbleibende Chancen Please use wechat to scan the code Bitte verwenden Sie WeChat, um den Code zu scannen BioDevices Unplugging of %1 device detected Das %1-Gerät wurde vom Stromnetz getrennt %1 device insertion detected %1 angeschlossenes Gerät erkannt ukui-biometric-manager Tools für die biometrische Verwaltung biometric Biologische Eigenschaften FingerPrint Fingerabdruck FingerVein Fingervenen Iris Iris Face Gesichtserkennung VoicePrint Stimmenausdruck ukey Sicherheitsschlüssel QRCode QR-Code Wechat 微信 BioDevicesWidget Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options Anmeldeoptionen Password Passwort Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Enter the ukey password Try it again Use other Devices Cancel Choose the option Invaild response " authentication will be canceld AUTHENTICATION CANCELED === BIOMETRIC DEVICES === Choose the device Sevice Name DISPLAY env User Display debug information Device short name UKEY AUTHENTICATION BIOMETRIC AUTHENTICATION Press Q or Esc to cancel BIOMETRIC AUTHENTICATION IS CLOSED AUTHENTICATION SUCCESS AUTHENTICATION FAILED Failed to verify %1, you still have %2 verification opportunities Unable to verify %1, please enter password. AUTHENTICATION END BIOMETRIC AUTHENTICATION END ukui-biometric-auth/bioauth-bin/i18n_ts/ky.ts0000664000175000017500000002755115167732644020101 0ustar fengfeng BioAuthWidget More 更多 Retry Ретри Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password Сырсөз Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 өтө көп ийгиликсиз аракеттер,, сураныч, сырсөз киргизүү. %1 authentication failure,there are still %2 remaining opportunities %1 аутентификациялык жетишсиздик,дагы эле %2 калган мүмкүнчүлүктөр бар Please use wechat to scan the code Кодду сканерлеу үчүн вечат колдонуңуз BioDevices Unplugging of %1 device detected %1 орнотмосунун өчүрүлүшү аныкталды %1 device insertion detected %1 түзмөк орнотмосу аныкталды ukui-biometric-manager укуи-биометриялык-менеджери biometric биометрия FingerPrint Манжа изи FingerVein Манжавейн Iris Ирис Face Бет VoicePrint VoicePrint ukey уики QRCode QRCode Wechat 微信 BioDevicesWidget Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options Кирүү параметрлери Password Сырсөз Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Enter the ukey password ukey جاشىرۇۇن نومۇرۇن كىرگىزىڭ Try it again قايرا سىناڭ Use other Devices باشقا شايمان ىشتەتىش Cancel ارعادان قالتىرىش Choose the option تانداش تۉرۉ Invaild response " ۅنۉمسۉز ىنكاس authentication will be canceld اتۇۇلدۇق تەكشەرىش ارعادان قالتىرلات AUTHENTICATION CANCELED اتۇۇلدۇق تەكشەرىش ارعادان قالتىرىلدى === BIOMETRIC DEVICES === = = = بىيولوگىيەلىك ايىرمالاندىرىش جابدۇۇسۇ = = = Choose the device باشقا شايمان تانداڭ Sevice Name تەيلۅۅ ناامى DISPLAY env كۅرسۅتۉۉ چۅيرۅسۉ User كەرەكتۅۅچۉ ناامى Display debug information تەڭشۅۅ ۇچۇردۇ كۅرسۅتۉۉ Device short name جابدۇۇسۇنۇن قىسقا ناامى UKEY AUTHENTICATION UKEY تولۇمدۇۇلۇق دالىلدۅ BIOMETRIC AUTHENTICATION بىيولوگىيەلىك ۅزگۅچۅلۉك ىسپاتى Press Q or Esc to cancel Q كۅرۉنۉشتۅرۉ Esc نى باسىپ ارعادان قالتىرىڭ BIOMETRIC AUTHENTICATION IS CLOSED بىئولوگىيەلىك ۅزگۅچۅلۉگۉ دالىلدۅ تاقالدى AUTHENTICATION SUCCESS اتۇۇلدۇق تەكشەرىش جەڭىشتۉۉ بولدۇ AUTHENTICATION FAILED اتۇۇلدۇق تەكشەرىش جەڭىلۉۉ بولدۇ . Failed to verify %1, you still have %2 verification opportunities ٪1 نى دالىلدۅ جەڭىلۉۉ بولدۇ ، سىزدە داعى ەلە ٪2 دالىلدۅ مۅۅرتۉ بار Unable to verify %1, please enter password. %1 نى دالىلدەگەلى بولبويت ، جاشىرۇۇن نومۇردۇ كىرگىزىڭ. AUTHENTICATION END اتۇۇلدۇق تەكشەرىش سوڭۇنا چىقتى. BIOMETRIC AUTHENTICATION END بىئولوگىيەلىك ۅزگۅچۅلۉك ىسپات بەرۉۉ ۇچۇ ukui-biometric-auth/bioauth-bin/i18n_ts/zh_CN.ts0000664000175000017500000001374715167732644020461 0ustar fengfeng QObject Enter the ukey password 输入ukey密码 Enter the ukey password 输入ukey密码\n Try it again 再试一次 Use other Devices 使用其他设备 Cancel 取消 Choose the option 选择选项 Invaild response " 不能识别的响应 " authentication will be canceld 认证将要被取消 AUTHENTICATION CANCELED 认证被取消 === BIOMETRIC DEVICES === === 生物识别设备 === Choose the device 选择设备 Sevice Name DISPLAY env User Display debug information Device short name UKEY AUTHENTICATION ukey认证 BIOMETRIC AUTHENTICATION 生物识别认证 Press Q or Esc to cancel 按Q或者Esc取消 BIOMETRIC AUTHENTICATION IS CLOSED 生物识别认证已关闭 AUTHENTICATION SUCCESS 认证成功 AUTHENTICATION FAILED 认证失败 Failed to verify %1, you still have %2 verification opportunities 验证%1失败,您还有%2次尝试机会 Unable to verify %1, please enter password. 无法验证%1,请输入密码. AUTHENTICATION END 认证结束 BIOMETRIC AUTHENTICATION END 生物识别认证结束 ukui-biometric-auth/bioauth-bin/i18n_ts/kk.ts0000664000175000017500000003007515167732644020056 0ustar fengfeng BioAuthWidget Form Пішін More 更多 Retry ретри Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password құпиясөз Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. % 1 Қате әрекеттер тым көп, құпия сөзіңізді енгізіңіз. %1 authentication failure,there are still %2 remaining opportunities % 1 аутентификациясы жаңылысқан және әлі де% 2 мүмкіндігі бар Please use wechat to scan the code Кодты сканерлеу үшін WeChat пайдалануыңызды сұраймын BioDevices Unplugging of %1 device detected % 1 құрылғы ажыратылды %1 device insertion detected % 1 құрылғы анықталды ukui-biometric-manager Биометриялық басқару құралдары biometric Биологиялық сипаттамалары FingerPrint саусақ ізі FingerVein Саусақ көктамырлары Iris ирис Face Бет тану VoicePrint Дауыстық із ukey Қауіпсіздік кілттері QRCode QR коды Wechat 微信 BioDevicesWidget Form Пішін Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options Кіру параметрлері Password құпиясөз Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Enter the ukey password ukey قۇپيا نۇمىردى كىرگىزىڭىز Try it again قاتە سىناڭ Use other Devices باسقا اسباب ٸستەتۋ Cancel كۇشىنەن قالدىرۋ Choose the option تالداۋ تۇرى Invaild response " ونٸمسٸز جاۋاپ authentication will be canceld ازاماتتىق تەكسەرۋ كۇشىنەن قالدىرىلدى AUTHENTICATION CANCELED ازاماتتىق تەكسەرۋ كۇشىنەن قالدىرىلدى === BIOMETRIC DEVICES === = = = بىيولوگىيەلىك پارىقتاندىرۋ اسپابٸ = = = Choose the device باسقا اسباب تالدا Sevice Name قىزىمەت مى DISPLAY env كورسەتۋ ورتا User الارمان مى Display debug information تەڭشەۋ حاباردٸ كورسەتۋ Device short name اسبابٸتٸڭ قىسقا مى UKEY AUTHENTICATION UKEY سالاۋاتىن دالەلدەۋ BIOMETRIC AUTHENTICATION بىيولوگىيەلىك ەرەكشەلىك كۋالٸكتٸ Press Q or Esc to cancel Q ياكي Esc نى باسٸپ كۇشىنەن قالدىرىڭ BIOMETRIC AUTHENTICATION IS CLOSED بىئولوگىيەلىك ەرەكشەلىكتى دالەلدەۋ جابٸلدٸ AUTHENTICATION SUCCESS ازاماتتىق تەكسەرۋ ناتيجەلى قالدى AUTHENTICATION FAILED ازاماتتىق تەكسەرۋ جەڭىلىپ قالدى. Failed to verify %1, you still have %2 verification opportunities ٪1 نى دالەلدەۋ جەڭىلىپ قالدى، سىزدە جانەدە ٪2 دالەلدەۋ ورايى بار Unable to verify %1, please enter password. %1 نى دالەلى بولمايدى، قۇپيا نۇمىردى كىرگىزىڭىز. AUTHENTICATION END ازاماتتىق تەكسەرۋ اياقتاتادى. BIOMETRIC AUTHENTICATION END بىئولوگىيەلىك ەرەكشەلىك دالەل بەرۋ ۇشى ukui-biometric-auth/bioauth-bin/i18n_ts/tr.ts0000664000175000017500000001512415167732644020074 0ustar fengfeng BioDevices FingerPrint Parmak İzi FingerVein Damar İzi Iris Göz Face Yüz Tanıma VoicePrint Ses İzi QObject Enter the ukey password Try it again Yeniden Dene Use other Devices Diğer Cihazları Kullan Cancel İptal Choose the option Seçeneği seçin Invaild response " Geçersiz cevap " authentication will be canceld AUTHENTICATION CANCELED KİMLİK DOĞRULAMA === BIOMETRIC DEVICES === === BİYOMETRİK CİHAZLAR === Choose the device Cihazı seçin Sevice Name Servis Adı DISPLAY env EKRAN env User Kullanıcı Display debug information Hata ayıklama bilgilerini görüntüle Device short name Cihaz kısa adı UKEY AUTHENTICATION BIOMETRIC AUTHENTICATION BİYOMETRİK KİMLİK DOĞRULAMA Press Q or Esc to cancel İptal etmek için Q veya Esc tuşuna basın BIOMETRIC AUTHENTICATION IS CLOSED AUTHENTICATION SUCCESS KİMLİK DOĞRULAMA AUTHENTICATION FAILED KİMLİK DOĞRULAMA BAŞARISIZ OLDU Failed to verify %1, you still have %2 verification opportunities Unable to verify %1, please enter password. AUTHENTICATION END BIOMETRIC AUTHENTICATION END BİYOMETRİK KİMLİK DOĞRULAMA SONU ukui-biometric-auth/bioauth-bin/i18n_ts/bo.ts0000664000175000017500000001347515167732644020056 0ustar fengfeng QObject Enter the ukey password Try it again Use other Devices Cancel Choose the option Invaild response " authentication will be canceld AUTHENTICATION CANCELED === BIOMETRIC DEVICES === Choose the device Sevice Name DISPLAY env User Display debug information Device short name UKEY AUTHENTICATION BIOMETRIC AUTHENTICATION Press Q or Esc to cancel BIOMETRIC AUTHENTICATION IS CLOSED AUTHENTICATION SUCCESS AUTHENTICATION FAILED Failed to verify %1, you still have %2 verification opportunities Unable to verify %1, please enter password. AUTHENTICATION END BIOMETRIC AUTHENTICATION END ukui-biometric-auth/bioauth-bin/i18n_ts/ug.ts0000664000175000017500000003022515167732644020061 0ustar fengfeng BioAuthWidget More 更多 Retry قايتا سىناپ بىقىڭ Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password مەخپىي نومۇر Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. 1-نومۇر مەغلۇپ بولغان سىناق قېتىم سانى زىيادە كۆپ، مەخپىي نومۇرنى كىرگۈزۈڭ %1 authentication failure,there are still %2 remaining opportunities بىر كىملىك دەلىللەش مەغلۇپ بولدى، يەنىلا ٪2 ئېشىپ قالغان پۇرسەت بار Please use wechat to scan the code ئۈندىداردا كود سۈپۈرۈڭ BioDevices Unplugging of %1 device detected تەكشۈرۈپ بايقىغان 1 ئۈسكۈنىنى تارتىپ چىقارماق %1 device insertion detected ٪1 ئۈسكۈنىنىڭ كىرگۈزۈلگەنلىكىنى تەكشۈرۈپ چىقماق ukui-biometric-manager بىئولوگىيەلىك ئالاھىدىلىك باشقۇرۇش قورالى biometric بىئولوگىيەلىك ئالاھىدىلىك FingerPrint بارماق ئىزى FingerVein ۋېنانى كۆرسىتىدۇ Iris رەڭدار پەردە Face ئادەم يۈزىنى پەرقلەندۈرۈش VoicePrint ئاۋاز سىزىقى ukey بىخەتەر ئاچقۇچ QRCode ئىككى ئۆلچەملىك كود Wechat 微信 BioDevicesWidget Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options تاللاش تۈرىگە كىرمەك Password مەخپىي نومۇر Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Enter the ukey password ukey مەخپىي نومۇرىنى كىرگۈزۈڭ Try it again قايتا سىناڭ Use other Devices باشقا ئۈسكۈنە ئىشلىتىش Cancel ئەمەلدىن قالدۇرۇش Choose the option تاللاش تۈرى Invaild response " ئۈنۈمسىز ئىنكاس authentication will be canceld سالاھىيەت تەكشۈرۈش ئەمەلدىن قالدۇرۇلىدۇ AUTHENTICATION CANCELED سالاھىيەت تەكشۈرۈش ئەمەلدىن قالدۇرۇلدى === BIOMETRIC DEVICES === = = = بىيولوگىيەلىك پەرقلەندۈرۈش ئۈسكۈنىسى = = = Choose the device باشقا ئۈسكۈنە تاللاڭ Sevice Name مۇلازىمەت نامى DISPLAY env كۆرسىتىش مۇھىتى User ئىشلەتكۈچى Display debug information تەڭشەش ئۇچۇرىنى كۆرسىتىش Device short name ئۈسكۈنىنىڭ قىسقا نامى UKEY AUTHENTICATION UKEY سالاھىيىتىنى دەلىللەش BIOMETRIC AUTHENTICATION بىيولوگىيەلىك ئالاھىدىلىك ئىسپاتى Press Q or Esc to cancel Q ياكى Esc نى بېسىپ ئەمەلدىن قالدۇرۇڭ BIOMETRIC AUTHENTICATION IS CLOSED بىئولوگىيەلىك ئالاھىدىلىكنى دەلىللەش تاقالدى AUTHENTICATION SUCCESS سالاھىيەت تەكشۈرۈش مۇۋەپپەقىيەتلىك بولدى AUTHENTICATION FAILED سالاھىيەت تەكشۈرۈش مەغلۇپ بولدى. Failed to verify %1, you still have %2 verification opportunities ٪1 دەلىللەش مەغلۇپ بولدى، سىزدە يەنە ٪2 دەلىللەش پۇرسىتى بار Unable to verify %1, please enter password. %1 نى دەلىللىگىلى بولمايدۇ، مەخپىي نومۇرنى كىرگۈزۈڭ. AUTHENTICATION END سالاھىيەت تەكشۈرۈش ئاخىرلاشتى. BIOMETRIC AUTHENTICATION END بىئولوگىيەلىك ئالاھىدىلىك ئىسپات بېرىش ئۇچى ukui-biometric-auth/bioauth-bin/i18n_ts/pt.ts0000664000175000017500000001140615167732644020071 0ustar fengfeng BioDevices FingerPrint Impressão digital FingerVein FingerVein Iris Íris Face Cara VoicePrint VoicePrint QObject Try it again Tente de novo Use other Devices Use outros dispositivos Cancel Cancelar Choose the option Escolha a opção Invaild response " Resposta Inválida \ " AUTHENTICATION CANCELED AUTENTICAÇÃO CANCELADA === BIOMETRIC DEVICES === === DISPOSITIVOS BIOMÉTRICOS === Choose the device Escolha o dispositivo Sevice Name Nome do Sevice DISPLAY env DISPLAY env User Do utilizador Display debug information Exibir informações de depuração Device short name Nome abreviado do dispositivo BIOMETRIC AUTHENTICATION AUTENTICAÇÃO BIOMÉTRICA Press Q or Esc to cancel Pressione Q ou Esc para cancelar AUTHENTICATION SUCCESS SUCESSO DE AUTENTICAÇÃO AUTHENTICATION FAILED AUTENTICAÇÃO FALHOU BIOMETRIC AUTHENTICATION END ENDEREÇO ​​DE AUTENTICAÇÃO BIOMÉTRICA authentication will be canceld Failed to verify %1, you still have %2 verification opportunities Unable to verify %1, please enter password. Enter the ukey password UKEY AUTHENTICATION BIOMETRIC AUTHENTICATION IS CLOSED AUTHENTICATION END ukui-biometric-auth/bioauth-bin/i18n_ts/bo_CN.ts0000664000175000017500000001361315167732644020430 0ustar fengfeng QObject DISPLAY env Choose the option གདམ་བྱ་འདེམ་པ། === BIOMETRIC DEVICES === === སྐྱེ་དངོས་ངོས་འཛིན་སྒྲིག་ཆས། === Display debug information བསྒྱུར་བཅོས་ཆ་འཕྲིན་མངོན་དུ་བཅུག་པ། Invaild response " ནུས་མེད་ཀྱི་དང་ལེན་ཨང་། AUTHENTICATION SUCCESS བདེན་དཔང་ངོས་འཛིན་ལེགས་གྲུབ། Try it again ཡང་བསྐྱར་ཚོད་ལྟ་ཐེངས་གཅིག Cancel མེད་པར་བཟོ་བ authentication will be canceld བདེན་དཔང་ངོས་འཛིན་མི་འགྱངས་པར་རྩིས་མེད་གཏོང་། AUTHENTICATION CANCELED བདེན་དཔང་ངོས་འཛིན་རྩིས་མེད་གཏོང་། Sevice Name ཞབས་ཞུའི་མིང་། Press Q or Esc to cancel Qམནན་པའམEscརྩིས་མེད། BIOMETRIC AUTHENTICATION སྐྱེ་དངོས་བརྟག་དཔྱད་བདེན་དཔང་ངོས་འཛིན། AUTHENTICATION FAILED བདེན་དཔང་ངོས་འཛིན་ཕམ་ཉེས་བྱུང་། Use other Devices སྒྲིག་ཆས་གཞན་བེད་སྤྱོད་བཏང་། BIOMETRIC AUTHENTICATION END སྐྱེ་དངོས་བརྟག་དཔྱད་བདེན་དཔང་ངོས་འཛིན་མཇུག་སྒྲིལ། Choose the device སྒྲིག་ཆས་འདེམ་པ། User སྤྱོད་མཁན། Device short name སྒྲིག་ཆས་ཀྱི་བསྡུས་མིང་། Failed to verify %1, you still have %2 verification opportunities ཚོད་ལྟས་ར་སྤྲོད་%1ཕམ་ཉེས་བྱུང་།ཁྱེད་རང་ད་དུང་ཡོད།%2ཚོད་ལྟ་བྱེད་པའི་གོ་སྐབས་ཤིག་རེད། Unable to verify %1, please enter password. ཚོད་ལྟས་ར་སྤྲོད་བྱེད་ཐབས་མེད%1,ཁྱོད་ཀྱིས་གསང་གྲངས་ནང་འཇུག་བྱེད་རོགས། UKEY AUTHENTICATION བདེ་འཇགས་ཀྱི་གསང་བའི་བདེན་དཔང་ར་སྤྲོད། BIOMETRIC AUTHENTICATION IS CLOSED སྐྱེ་དངོས་ཀྱི་ངོས་འཛིན་ཁས་ལེན་བྱས་པ་སྒོ་བརྒྱབ་ཟིན། AUTHENTICATION END བདེན་དཔང་ར་སྤྲོད་མཇུག་བསྒྲི Enter the ukey password བདེ་འཇགས་ཀྱི་གསང་བའི་གསང་བའི་ཨང་གྲངས་ནང་འཇུག་བྱེད་དགོས། ukui-biometric-auth/bioauth-bin/i18n_ts/vi.ts0000664000175000017500000001430715167732644020067 0ustar fengfeng QObject Enter the ukey password Nhập mật khẩu UKey Enter the ukey password Nhập mật khẩu ukey Try it again Thử lại một lần nữa Use other Devices Sử dụng thiết bị khác Cancel Hủy Choose the option Chọn tùy chọn Invaild response " Phản hồi Invaild " authentication will be canceld Xác thực sẽ bị hủy bỏ AUTHENTICATION CANCELED XÁC THỰC BỊ HỦY === BIOMETRIC DEVICES === === THIẾT BỊ SINH TRẮC HỌC === Choose the device Chọn thiết bị Sevice Name DISPLAY env User Tên người dùng Display debug information Device short name Tên ngắn thiết bị UKEY AUTHENTICATION XÁC THỰC UKEY BIOMETRIC AUTHENTICATION XÁC THỰC SINH TRẮC HỌC Press Q or Esc to cancel Ấn Q hoặc Esc để hủy BIOMETRIC AUTHENTICATION IS CLOSED Xác thực sinh trắc học đã bị tắt AUTHENTICATION SUCCESS XÁC THỰC THÀNH CÔNG AUTHENTICATION FAILED Xác thực thất bại Failed to verify %1, you still have %2 verification opportunities Xác thực %1 thất bại,bạn còn %2 lần thử Unable to verify %1, please enter password. Không thể xác minh %1, vui lòng nhập mật khẩu. AUTHENTICATION END KẾT THÚC XÁC THỰC BIOMETRIC AUTHENTICATION END Xác thực sinh trắc học đã kết thúc ukui-biometric-auth/bioauth-bin/i18n_ts/mn.ts0000664000175000017500000003231015167732644020055 0ustar fengfeng BioAuthWidget More 更多 Retry ᠳᠠᠬᠢᠨ ᠲᠤᠷᠰᠢᠬᠤ Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 ᠢᠯᠠᠭᠳᠠᠭᠰᠠᠨ ᠲᠤᠷᠰᠢᠬᠤ ᠤᠳᠠᠭ᠎ᠠ ᠲᠣᠭ᠎ᠠ ᠬᠡᠳᠦ ᠣᠯᠠᠨ ᠂ ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠣᠷᠣᠭᠤᠯᠤᠭᠠᠷᠠᠢ ᠃ %1 authentication failure,there are still %2 remaining opportunities %1 ᠪᠡᠶ᠎ᠡ᠎ᠶ᠋ᠢᠨ ᠬᠢᠷᠢ᠎ᠶ᠋ᠢᠨ ᠰᠢᠯᠭᠠᠨ ᠪᠠᠲᠤᠯᠠᠯᠲᠠ ᠢᠯᠠᠭᠳᠠᠪᠠ ᠂ ᠮᠥᠨ %2 ᠦᠯᠡᠳᠡᠬᠦ ᠲᠣᠬᠢᠶᠠᠯ ᠪᠣᠢ Please use wechat to scan the code ᠸᠢᠴᠠᠲ᠎ᠢ᠋ᠶ᠋ᠠᠷ ᠦᠰᠦᠭ ᠰᠢᠷᠪᠢᠬᠦ ᠪᠣᠯᠪᠠᠤ BioDevices Unplugging of %1 device detected %1 ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ᠎ᠶ᠋ᠢ ᠰᠤᠭᠤᠯᠵᠤ ᠭᠠᠷᠭᠠᠨ ᠠ %1 device insertion detected %1 ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ ᠬᠠᠪᠴᠢᠭᠤᠯᠤᠭᠰᠠᠨ᠎ᠢ᠋ ᠪᠠᠢᠴᠠᠭᠠᠨ ᠣᠯᠪᠠ ukui-biometric-manager ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ᠎ᠤ᠋ᠨ ᠣᠨᠴᠠᠯᠢᠭ ᠬᠠᠮᠢᠶᠠᠷᠤᠯᠲᠠ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠵᠢ biometric ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ᠎ᠤ᠋ᠨ ᠣᠨᠴᠠᠯᠢᠭ FingerPrint ᠬᠤᠷᠤᠭᠤᠨ ᠬᠡ FingerVein ᠬᠤᠷᠤᠭᠤᠨ ᠨᠠᠮᠵᠢᠭᠤᠨ ᠰᠤᠳᠠᠰᠤ Iris ᠰᠣᠯᠣᠩᠭ᠎ᠠ ᠪᠦᠷᠬᠦᠭᠦᠯ Face ᠬᠥᠮᠦᠨ᠎ᠦ᠌ ᠨᠢᠭᠤᠷ ᠲᠠᠨᠢᠬᠤ VoicePrint ᠳᠠᠭᠤᠨ ᠡᠷᠢᠶᠡᠨ ukey ᠠᠶᠤᠯᠭᠦᠢ ᠨᠢᠭᠤᠴᠠ ᠲᠦᠯᠬᠢᠭᠦᠷ QRCode ᠬᠣᠶᠠᠷ ᠬᠡᠮᠵᠢᠯᠲᠦ ᠺᠣᠳ᠋ Wechat 微信 BioDevicesWidget Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options ᠲᠡᠮᠳᠡᠭᠯᠡᠬᠦ ᠰᠤᠩᠭᠤᠭᠳᠠᠬᠤᠨ Password ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Enter the ukey password ukey ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠢ᠋ ᠣᠷᠣᠭᠤᠯᠬᠤ Try it again ᠳᠠᠬᠢᠵᠤ ᠳᠤᠷᠰᠢᠬᠤ Use other Devices ᠪᠤᠰᠤᠳ ᠳᠦᠬᠦᠬᠡᠷᠦᠮᠵᠢ ᠵᠢ ᠬᠡᠷᠡᠭᠯᠡᠬᠦ Cancel ᠦᠬᠡᠢᠰᠬᠡᠬᠦ Choose the option ᠰᠤᠩᠭᠤᠭᠳᠠᠬᠤᠨ ᠢ᠋ ᠰᠣᠩᠭᠣᠬᠤ Invaild response " ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠵᠤ ᠪᠣᠯᠬᠤ ᠥᠬᠡᠢ ᠳᠤᠰᠬᠠᠯ " authentication will be canceld ᠬᠡᠷᠡᠴᠢᠯᠡᠯ ᠤᠳᠠᠬᠤ ᠥᠬᠡᠢ ᠦᠬᠡᠢᠰᠬᠡᠭᠳᠡᠨ᠎ᠡ AUTHENTICATION CANCELED ᠬᠡᠷᠡᠴᠢᠯᠡᠯ ᠦᠬᠡᠢᠰᠬᠡᠭᠳᠡᠪᠡ === BIOMETRIC DEVICES === === ᠪᠢᠤᠯᠤᠬᠢ ᠵᠢᠨ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠳᠦᠬᠦᠬᠡᠷᠦᠮᠵᠢ=== Choose the device ᠳᠦᠬᠦᠬᠡᠷᠦᠮᠵᠢ ᠰᠣᠩᠭᠣᠬᠤ Sevice Name Sevice Name DISPLAY env DISPLAY env User ᠬᠡᠷᠡᠭᠯᠡᠭᠴᠢ Display debug information ᠳᠤᠬᠢᠷᠠᠭᠤᠯᠤᠭᠰᠠᠨ ᠰᠤᠷᠠᠭ ᠵᠠᠩᠬᠢ ᠢᠯᠡᠷᠡᠬᠦᠯᠬᠦ Device short name ᠨᠢᠭᠡ ᠳᠦᠬᠦᠬᠡᠷᠦᠮᠵᠢ ᠰᠤᠩᠭᠤᠨ ᠳᠤᠭᠳᠠᠭᠠᠭᠠᠷᠠᠢ UKEY AUTHENTICATION ukey ᠬᠡᠷᠡᠴᠢᠯᠡᠯ BIOMETRIC AUTHENTICATION ᠪᠢᠤᠯᠤᠬᠢ ᠵᠢ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠬᠡᠷᠡᠴᠢᠯᠡᠯ Press Q or Esc to cancel Q ᠪᠤᠶᠤEsc ᠢ᠋\ ᠵᠢ ᠳᠠᠷᠤᠵᠤ ᠦᠬᠡᠢᠰᠬᠡᠬᠦ BIOMETRIC AUTHENTICATION IS CLOSED ᠪᠢᠤᠯᠤᠬᠢ ᠵᠢ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠬᠡᠷᠡᠴᠢᠯᠡᠯ ᠢ᠋ ᠨᠢᠬᠡᠨᠳᠡ ᠬᠠᠭᠠᠪᠠ AUTHENTICATION SUCCESS ᠬᠡᠷᠡᠴᠢᠯᠡᠪᠡ AUTHENTICATION FAILED ᠬᠡᠷᠡᠴᠢᠯᠡᠵᠤ ᠴᠢᠳᠠᠭᠰᠠᠨ ᠥᠬᠡᠢ Failed to verify %1, you still have %2 verification opportunities %1 ᠢ᠋\ ᠵᠢ ᠪᠠᠳᠤᠯᠠᠭᠠᠵᠢᠭᠤᠯᠵᠤ ᠴᠢᠳᠠᠭᠰᠠᠨ ᠥᠬᠡᠢ᠂ ᠲᠠ ᠪᠠᠰᠠ %2 ᠤᠳᠠᠭᠠᠨ ᠤ᠋ ᠳᠤᠷᠰᠢᠬᠤ ᠵᠠᠪᠰᠢᠶᠠᠨ ᠪᠤᠢ Unable to verify %1, please enter password. %1 ᠢ᠋\ ᠵᠢ ᠪᠠᠳᠤᠯᠠᠭᠠᠵᠢᠭᠤᠯᠬᠤ ᠵᠢᠨ ᠠᠷᠭ᠎ᠠ ᠥᠬᠡᠢ᠂ ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠵᠢᠨᠨ ᠤᠷᠤᠭᠤᠯᠤᠨ᠎ᠠ ᠤᠤ᠃ AUTHENTICATION END ᠬᠡᠷᠡᠴᠢᠯᠡᠯ ᠳᠠᠭᠤᠰᠪᠠ BIOMETRIC AUTHENTICATION END ᠪᠢᠤᠯᠤᠬᠢ ᠵᠢ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠬᠡᠷᠡᠴᠢᠯᠡᠯ ᠳᠠᠭᠤᠰᠪᠠ ukui-biometric-auth/bioauth-bin/i18n_ts/fr.ts0000664000175000017500000002603215167732644020056 0ustar fengfeng BioAuthWidget Form Forme More 更多 Retry réessayer Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password mot de passe Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 Il y a trop de tentatives infructueuses, veuillez saisir votre mot de passe. %1 authentication failure,there are still %2 remaining opportunities %1 authentification a échoué et il reste encore %2 chances Please use wechat to scan the code Veuillez utiliser WeChat pour scanner le code BioDevices Unplugging of %1 device detected L’appareil %1 a été débranché %1 device insertion detected %1 périphérique branché détecté ukui-biometric-manager Outils de gestion biométrique biometric Caractéristiques biologiques FingerPrint empreinte digitale FingerVein Veines des doigts Iris iris Face Reconnaissance faciale VoicePrint Voiceprint ukey Clés de sécurité QRCode Code QR Wechat 微信 BioDevicesWidget Form Forme Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options Options de connexion Password mot de passe Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Enter the ukey password Try it again Use other Devices Cancel Choose the option Invaild response " authentication will be canceld AUTHENTICATION CANCELED === BIOMETRIC DEVICES === Choose the device Sevice Name DISPLAY env User Display debug information Device short name UKEY AUTHENTICATION BIOMETRIC AUTHENTICATION Press Q or Esc to cancel BIOMETRIC AUTHENTICATION IS CLOSED AUTHENTICATION SUCCESS AUTHENTICATION FAILED Failed to verify %1, you still have %2 verification opportunities Unable to verify %1, please enter password. AUTHENTICATION END BIOMETRIC AUTHENTICATION END ukui-biometric-auth/bioauth-bin/i18n_ts/es.ts0000664000175000017500000002571315167732644020063 0ustar fengfeng BioAuthWidget Form Forma More 更多 Retry Reintentar Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password Contraseña Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 Demasiados intentos fallidos, ingrese la contraseña. %1 authentication failure,there are still %2 remaining opportunities %1 error de autenticación, todavía quedan %2 oportunidades Please use wechat to scan the code Utilice wechat para escanear el código BioDevices Unplugging of %1 device detected Se ha detectado la desconexión del dispositivo %1 %1 device insertion detected %1 inserción de dispositivo detectada ukui-biometric-manager ukui-gestor-biométrico biometric biométrico FingerPrint Huellas FingerVein FingerVein Iris Iris Face Cara VoicePrint Huella de voz ukey ukey QRCode QRCode Wechat 微信 BioDevicesWidget Form Forma Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options Opciones de inicio de sesión Password Contraseña Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Enter the ukey password Try it again Use other Devices Cancel Choose the option Invaild response " authentication will be canceld AUTHENTICATION CANCELED === BIOMETRIC DEVICES === Choose the device Sevice Name DISPLAY env User Display debug information Device short name UKEY AUTHENTICATION BIOMETRIC AUTHENTICATION Press Q or Esc to cancel BIOMETRIC AUTHENTICATION IS CLOSED AUTHENTICATION SUCCESS AUTHENTICATION FAILED Failed to verify %1, you still have %2 verification opportunities Unable to verify %1, please enter password. AUTHENTICATION END BIOMETRIC AUTHENTICATION END ukui-biometric-auth/bioauth-bin/i18n_ts/zh_HK.ts0000664000175000017500000001405415167732644020453 0ustar fengfeng QObject Enter the ukey password 輸入 ukey 密碼 Enter the ukey password 輸入 ukey 密碼 Try it again 再試一次 Use other Devices 使用其他設備 Cancel 取消 Choose the option 選擇選項 Invaild response " Invaild 回應 ” authentication will be canceld 身份驗證將被取消 AUTHENTICATION CANCELED 身份驗證已取消 === BIOMETRIC DEVICES === === 生物識別設備 === Choose the device 選擇設備 Sevice Name 服務名稱 DISPLAY env 顯示環境 User 使用者 Display debug information 顯示調試資訊 Device short name 設備簡稱 UKEY AUTHENTICATION UKEY 身份驗證 BIOMETRIC AUTHENTICATION 生物識別身份驗證 Press Q or Esc to cancel 按 Q 或 Esc 鍵取消 BIOMETRIC AUTHENTICATION IS CLOSED 生物識別身份驗證已關閉 AUTHENTICATION SUCCESS 身份驗證成功 AUTHENTICATION FAILED 身份驗證失敗 Failed to verify %1, you still have %2 verification opportunities 驗證 %1 失敗,您仍有 %2 驗證機會 Unable to verify %1, please enter password. 無法驗證 %1,請輸入密碼。 AUTHENTICATION END 鑒權結束 BIOMETRIC AUTHENTICATION END 生物識別認證結束 ukui-biometric-auth/polkit-agent/0000775000175000017500000000000015167732644016004 5ustar fengfengukui-biometric-auth/polkit-agent/src/0000775000175000017500000000000015167732644016573 5ustar fengfengukui-biometric-auth/polkit-agent/src/mainwindow.cpp0000664000175000017500000016615715167732644021473 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "mainwindow.h" #include "ui_mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../common/qt_matrix_compat.h" #include "bioauthwidget.h" #include #include #include #include "generic.h" #include "biotypes.h" #include "modeButton.h" #include #define _(string) gettext(string) extern void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed); MainWindow::MainWindow(QWidget *parent) : kdk::KDialog(parent) , ui(new Ui::MainWindow) , users(new Users(this)) , enableBioAuth(false) , receiveBioPAM(false) , authMode(UNDEFINED) , useDoubleAuth(false) , m_timer(nullptr) , w_timer(nullptr) , isLockingFlg(false) , m_nCurLockMin(0) , isbioSuccess(false) { ui->setupUi(this); mainLayout()->addLayout(ui->verticalLayout_2); pam_tally_init(); // // 登录选项 m_labelTip = new KALabel(); m_labelTip->setText(""); m_labelTip->setFixedHeight(30); m_labelTip->hide(); m_loginOptsWidget = new LoginOptionsWidget(); m_loginOptsWidget->hide(); ui->titleTipLayout->addWidget(m_labelTip); ui->loginOptionsLayout->setAlignment(Qt::AlignTop | Qt::AlignCenter); ui->loginOptionsLayout->addWidget(m_loginOptsWidget); ui->loadingUkeyWidget->adjustSize(); ui->loadingUkeyWidget->hide(); ui->widgetUkeyAuth->hide(); ui->loadingUkeyBtn->setAttribute(Qt::WA_TransparentForMouseEvents, true); ui->ukeyPassword->setEchoMode(QLineEdit::Password); ui->loadingUkeyLbl->setText(tr("Insert the ukey into the USB port")); ui->loadingUkeyLbl->setAlignment(Qt::AlignTop | Qt::AlignHCenter); ui->ukeyTipLbl->setText(tr("Enter the ukey password")); ui->ukeyPassword->setPlaceholderText(tr("Input Password")); ui->btnCancel->setAutoDefault(false); ui->btnCancel->setDefault(false); maxFailedTimes = bioDevices.getFailedTimes(); isHiddenSwitchButton = bioDevices.GetHiddenSwitchButton(); closeButton()->setToolTip(tr("Close")); // 连接登录选项信号响应槽 connect(m_loginOptsWidget, &LoginOptionsWidget::optionSelected, this, &MainWindow::onOptionSelected); connect(m_loginOptsWidget, &LoginOptionsWidget::notifyOptionsChange, this, &MainWindow::onNotifyOptionsChanged); connect(m_loginOptsWidget, &LoginOptionsWidget::authComplete, this, &MainWindow::onLoginOptionsAuthCompleted); connect(m_loginOptsWidget, &LoginOptionsWidget::updateAuthMsg, this, &MainWindow::onUpdateBioAuthMsg); connect(m_loginOptsWidget, &LoginOptionsWidget::updateWndSize, this, &MainWindow::onUpdateWndSize); QFile qssFile(":/qss/src/main.qss"); qssFile.open(QIODevice::ReadOnly); setStyleSheet(qssFile.readAll()); qssFile.close(); ui->lePassword->installEventFilter(this); // 初始化UI状态 switchWidget(UNDEFINED); editIcon(); ui->lblContent->adjustSize(); ui->lblContent->hide(); ui->lblMessage->setFixedSize(372, 30); ui->widgetPasswdAuth->adjustSize(); ui->widgetUkeyAuth->adjustSize(); ui->cmbUsers->view()->setTextElideMode(Qt::ElideRight); ui->cmbUsers->setFixedHeight(36); ui->lePassword->setFixedHeight(36); ui->btnBioAuth->hide(); ui->returnButton->hide(); ui->btnAuth->setProperty("isImportant", true); ui->btnCancel->setProperty("useButtonPalette", true); settings = new QGSettings("org.ukui.style", "", this); fontSize = settings->get("system-font-size").toInt(); connect(settings, &QGSettings::changed, this, &MainWindow::onConfigurationChanged); QDBusInterface *interfaceScreensaver = new QDBusInterface("org.ukui.ScreenSaver", "/", "org.ukui.ScreenSaver", QDBusConnection::sessionBus()); connect(interfaceScreensaver, SIGNAL(lock()), this, SLOT(onLockStatus())); connect(interfaceScreensaver, SIGNAL(unlock()), this, SLOT(onUnlockStatus())); } MainWindow::~MainWindow() { delete ui; } void MainWindow::onConfigurationChanged(QString key) { if (key == "systemFontSize") { m_loginOptsWidget->updateUIStatus(false); fontSize = settings->get("system-font-size").toInt(); } if (key == "iconThemeName") { setIcon(app_IconName); } if (key == "styleName") { QPalette pe; if (no_changes) { pe.setColor(QPalette::Text, Qt::red); m_labelTip->setPalette(pe); } else { QColor color = palette().color(QPalette::Text); QPalette pal(this->palette()); pal.setColor(QPalette::Text, QColor(color)); m_labelTip->setPalette(pal); } } } void MainWindow::restart_bio_identify() { DeviceInfoPtr device = bioDevices.getDefaultDevice(getUid(userName)); if (device) { m_loginOptsWidget->startAuth(device, getUid(userName)); setMessage(tr("Please enter your password or enroll your fingerprint ")); } } void MainWindow::closeEvent(QCloseEvent *event) { if (m_loginOptsWidget) { m_loginOptsWidget->stopAuth(); } m_failMap.clear(); emit canceled(); return kdk::KDialog::closeEvent(event); } void MainWindow::setUkeyTypeTip(QString text) { QString textTip = text; if (!textTip.isEmpty()) { QPalette pe; pe.setColor(QPalette::Text, Qt::red); ui->ukeyMessage->setPalette(pe); ui->ukeyMessage->setText(textTip); ui->ukeyMessage->setToolTip(text); ui->ukeyMessage->show(); } else { ui->ukeyMessage->hide(); } } void MainWindow::startLoadingUkey() { m_loadingPixmap = QIcon::fromTheme("ukui-loading-0-symbolic").pixmap(27, 27); ui->loadingUkeyBtn->setIcon(m_loadingPixmap); ui->loadingUkeyBtn->setIconSize(QSize(27, 27)); ui->loadingUkeyWidget->adjustSize(); ui->cmbUsers->hide(); ui->widgetUkeyAuth->hide(); ui->lePassword->hide(); ui->widgetPasswdAuth->hide(); isLoadingUkey = true; ui->loadingUkeyWidget->show(); if (!m_loadingTimer) { m_loadingTimer = new QTimer(this); m_loadingTimer->setInterval(150); connect(m_loadingTimer, &QTimer::timeout, this, &MainWindow::updateLoadingPixmap); } m_loadingTimer->start(); } void MainWindow::stopLoadingUkey() { isLoadingUkey = false; if (m_loadingTimer) { m_loadingTimer->stop(); } ui->loadingUkeyWidget->hide(); // ui->cmbUsers->show(); // ui->widgetUkeyAuth->show(); } void MainWindow::updateLoadingPixmap() { QMatrix matrix; matrix.rotate(90.0); m_loadingPixmap = QtPixmapCompat::transformedPixmap(m_loadingPixmap, matrix, Qt::FastTransformation); ui->loadingUkeyBtn->setIcon(QIcon(m_loadingPixmap)); } void MainWindow::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QStyleOption *option = new QStyleOption(); QPainter p(this); p.setRenderHint(QPainter::Antialiasing); QPainterPath rectPath; rectPath.addRoundedRect(this->rect().adjusted(0, 0, 0, 0), 0, 0); // 画一个黑底 QPixmap pixmap(this->rect().size()); pixmap.fill(Qt::transparent); QPainter pixmapPainter(&pixmap); pixmapPainter.setRenderHint(QPainter::Antialiasing); pixmapPainter.setPen(Qt::transparent); pixmapPainter.setBrush(QColor(0, 0, 0, 100)); pixmapPainter.drawPath(rectPath); pixmapPainter.end(); // 模糊这个黑底 QImage img = pixmap.toImage(); qt_blurImage(img, 10, false, false); // 挖掉中心 pixmap = QPixmap::fromImage(img); QPainter pixmapPainter2(&pixmap); pixmapPainter2.setRenderHint(QPainter::Antialiasing); pixmapPainter2.setCompositionMode(QPainter::CompositionMode_Clear); pixmapPainter2.setPen(Qt::transparent); pixmapPainter2.setBrush(Qt::transparent); pixmapPainter2.drawPath(rectPath); // 绘制阴影 p.drawPixmap(this->rect(), pixmap, pixmap.rect()); // 绘制一个背景 p.save(); p.fillPath(rectPath, option->palette.color(QPalette::Base)); p.restore(); } bool MainWindow::eventFilter(QObject *obj, QEvent *event) { if (obj == ui->lePassword) { if (event->type() == QEvent::KeyPress) { // 禁止复制粘贴功能。 QKeyEvent *keyEvent = static_cast(event); if (keyEvent->matches(QKeySequence::Copy) || keyEvent->matches(QKeySequence::Cut) || keyEvent->matches(QKeySequence::Paste)) { event->ignore(); return true; } } if (event->type() == QEvent::MouseButtonRelease) { // 禁用鼠标中键 QMouseEvent *mouseevent = static_cast(event); #if QT_VERSION_MAJOR == 6 if (mouseevent->button() == Qt::MiddleButton) { #else if (mouseevent->button() == Qt::MidButton) { #endif event->ignore(); return true; } } } return kdk::KDialog::eventFilter(obj, event); } void MainWindow::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: { break; } default: { kdk::KDialog::keyPressEvent(event); break; } } } /*** main ***/ void MainWindow::on_cmbUsers_currentTextChanged(const QString &userName) { qDebug() << "user changed to " << userName; m_loginOptsWidget->stopAuth(); if (m_bioTimer && m_bioTimer->isActive()) m_bioTimer->stop(); authMode = UNDEFINED; QList accountUsers = users->getUsers(); this->userName = userName; for (UserItem user : accountUsers) { if (user.realName == userName) { this->userName = user.name; } } m_deviceInfo = DeviceInfoPtr(); ui->lblMessage->clear(); ui->lblMessage->setToolTip(""); setMessage(""); isLockingFlg = false; emit userChanged(this->userName); } int MainWindow::enable_biometric_authentication() { char conf_file[] = GET_STR(CONFIG_FILE); FILE *file; char line[1024], is_enable[16]; int i; if ((file = fopen(conf_file, "r")) == NULL) { return 0; } while (fgets(line, sizeof(line), file)) { i = sscanf(line, "EnableAuth=%s\n", is_enable); if (i > 0) { break; } } fclose(file); if (!strcmp(is_enable, "true")) return 1; return 0; } void MainWindow::on_btnDetails_clicked() { /* if(ui->widgetDetails->isHidden()) { ui->widgetDetails->show(); ui->btnDetails->setIcon(QIcon(":/image/assets/arrow_down.svg")); // resize(width(), height() + ui->widgetDetails->height()); } else { ui->widgetDetails->hide(); ui->btnDetails->setIcon(QIcon(":/image/assets/arrow_right.svg")); // resize(width(), height() - ui->widgetDetails->height()); } adjustSize();*/ } void MainWindow::on_btnCancel_clicked() { close(); } void MainWindow::on_btnAuth_clicked() { if (doNotNeedAuth) { emit yesPrompted(); return; } if (ui->widgetUkeyAuth->isVisible()) { on_ukeyPassword_returnPressed(); } else { on_lePassword_returnPressed(); } } void MainWindow::onShowYesPrompt() { doNotNeedAuth = true; ui->widgetPasswdAuth->hide(); ui->cmbUsers->hide(); ui->btnBioAuth->hide(); ui->returnButton->hide(); ui->btnAuth->show(); } void MainWindow::onLockStatus() { // m_loginOptsWidget->stopAuth(); m_loginOptsWidget->lockStatusChanged(true); } void MainWindow::onUnlockStatus() { // m_loginOptsWidget->readDevicesInfo(); m_loginOptsWidget->lockStatusChanged(false); startBioAuth(); } /*** pagePassword ***/ void MainWindow::editIcon() { m_modeButton = new ModeButton(ui->lePassword); m_modeButton->setFocusPolicy(Qt::NoFocus); connect(m_modeButton, &QPushButton::clicked, this, [=]() { if (ui->lePassword->echoMode() == QLineEdit::Password) { ui->lePassword->setEchoMode(QLineEdit::Normal); } else { ui->lePassword->setEchoMode(QLineEdit::Password); } }); QHBoxLayout *layout = new QHBoxLayout(ui->lePassword); layout->addStretch(); layout->addWidget(m_modeButton); layout->setContentsMargins(0, 0, 8, 0); ui->lePassword->setTextMargins(1, 1, 4 + m_modeButton->width(), 1); } void MainWindow::on_ukeyPassword_returnPressed() { if (m_loginOptsWidget && m_deviceInfo) { m_loginOptsWidget->SetExtraInfo(ui->ukeyPassword->text(), "pincode"); m_loginOptsWidget->startAuth(m_deviceInfo, getUid(userName)); } } void MainWindow::on_lePassword_returnPressed() { emit accept(ui->lePassword->text()); ui->btnAuth->hide(); ui->btnLoading->show(); setMessage(""); if (!w_timer) { w_timer = new QTimer(this); w_timer->setInterval(150); connect(w_timer, &QTimer::timeout, this, &MainWindow::updatePixmap); } m_waitingPixmap = QIcon::fromTheme("ukui-loading-0-symbolic").pixmap(24, 24); ui->btnLoading->setIcon(QIcon(m_waitingPixmap)); w_timer->start(); // switchWidget(UNDEFINED); // setMessage(tr("in authentication, please wait...")); hasSendPassword = true; } void MainWindow::on_btnBioAuth_clicked() { emit switchToBiometric(); authMode = BIOMETRIC; } void MainWindow::on_returnButton_clicked() { m_loginOptsWidget->stopAuth(); accept(BIOMETRIC_IGNORE); } /*** end of control's slot ***/ /*** public member ***/ void MainWindow::setIcon(const QString &iconName) { // QIcon::setThemeName("ukui-icon-theme"); app_IconName = iconName; if (!QIcon::hasThemeIcon("ukui-polkit")) { QDir iconsDir("/usr/share/icons"); auto themesList = iconsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); qDebug() << themesList; for (auto theme : themesList) { QIcon::setThemeName(theme); if (QIcon::hasThemeIcon("ukui-polkit")) { qDebug() << theme << "has ukui-polkit icon"; break; } } } QPixmap icon = QIcon::fromTheme("ukui-polkit").pixmap(64, 64); QPixmap actionIcon = QIcon::fromTheme(app_IconName).pixmap(32, 32); QPainter painter; painter.begin(&icon); QRect rect(32, 32, 32, 32); painter.drawPixmap(rect, actionIcon); painter.end(); setWindowIcon(icon); // ui->lblIcon->setPixmap(icon); } void MainWindow::setHeader(const QString &text) { if (is_Mavis) ui->lblHeader->setText(tr("This operation requires the administrator's authorization. " "Please enter your password to allow this operation.")); else ui->lblHeader->setText(text); ui->lblHeader->adjustSize(); ui->lblContent->setText(tr("A program is attempting to perform an action that requires privileges." "It requires authorization to perform the action.")); ui->lblContent->adjustSize(); } void MainWindow::setUsers(const QStringList &usersList) { if (usersList.isEmpty()) return; if (usersList.size() == 1) { UserItem user = users->getUserByName(usersList.at(0)); if (user.realName != "") { userName = user.realName; } else { userName = usersList.at(0); } } QList accountUsers = users->getUsers(); for (QString identifyUser : usersList) { bool isFoundAccount = false; for (UserItem user : accountUsers) { if (identifyUser == user.name) { if (user.realName != "") ui->cmbUsers->addItem(user.realName); else ui->cmbUsers->addItem(user.name); isFoundAccount = true; break; } } if (!isFoundAccount) { ui->cmbUsers->addItem(identifyUser); } } ui->cmbUsers->show(); // ui->cmbUsers->adjustSize(); } /* void MainWindow::setDetails(const QString &subPid, const QString &callerPid, const QString &actionId, const QString &actionDesc, const QString vendorName, const QString vendorUrl) { ui->lblSubjectPid->setText(subPid); ui->lblCallerPid->setText(callerPid); ui->lblActionId->setText(actionId); ui->lblActionDesc->setText(actionDesc); QString vendor = QString("%2").arg(vendorUrl).arg(vendorName); ui->lblVendor->setText(vendor); } */ void MainWindow::setPrompt(const QString &text, bool echo) { QString prompt = text; if (text == "Input Password") { prompt = tr("Input Password"); } else if (text == "Password: " || text == "Password:") { prompt = tr("Password: "); } else if (text == "_Password: ") { prompt = tr("_Password: "); } else if (text == "_Password:") { prompt = tr("_Password:"); } if (!m_timer) { m_timer = new QTimer(this); m_timer->setInterval(200); connect(m_timer, &QTimer::timeout, this, &MainWindow::unlock_countdown); } // qDebug() << "6666"; m_timer->start(); unlock_countdown(); ui->lePassword->clear(); ui->lePassword->setPlaceholderText(prompt); // switchWidget(PASSWORD); } /* 转换pam英文提示,目前转换的就3个翻译 Authenticated failed, account locked! Authenticated failed, 1 login attemps left Account locked, 4 minutes left */ QString MainWindow::check_is_pam_message(QString text) { if (text.isEmpty()) { return text; } setlocale(LC_ALL, ""); bindtextdomain("Linux-PAM", "/usr/share/locale"); bind_textdomain_codeset("Linux-PAM", "UTF-8"); textdomain("Linux-PAM"); char *str; QString strTrans = ""; QByteArray ba = text.toLocal8Bit(); // must str = ba.data(); char l_str[1024]; int a, b; // 兼容旧版本翻译,以及适配新版本翻译 // 因为不知道什么原因,pam发过来的始终为英文,因此这里主动加载pam的翻译文件,使用gettext获取翻译 if (text.contains("attemps", Qt::CaseSensitive) && sscanf(str, "Authenticated failed, %d login attemps left", &a)) snprintf(l_str, 1024, _("Authenticated failed, %d login attemps left"), a); else if ( text.contains("attempts", Qt::CaseSensitive) && sscanf(str, "Authenticated failed, %d login attempts left", &a)) snprintf(l_str, 1024, _("Authenticated failed, %d login attempts left"), a); else if ( text.contains("attempt", Qt::CaseSensitive) && sscanf(str, "Authenticated failed, %d login attempt left", &a)) snprintf(l_str, 1024, _("Authenticated failed, %d login attempt left"), a); else if (text.contains("days", Qt::CaseSensitive) && sscanf(str, "Account locked, %d days left", &a)) { // 这里的消息是多个字符串拼接起来的,无法在翻译文件中找到对应的句子,只能自己翻译 strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("days left"); return strTrans; } else if (text.contains("hours", Qt::CaseSensitive) && sscanf(str, "Account locked, %d hours left", &a)) { strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("hours left"); return strTrans; } else if (text.contains("minutes", Qt::CaseSensitive) && sscanf(str, "Account locked, %d minutes left", &a)) { strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("minutes left"); return strTrans; } else if (text.contains("seconds", Qt::CaseSensitive) && sscanf(str, "Account locked, %d seconds left", &a)) { strTrans = tr("Account locked,") + QString("%1 ").arg(a) + tr("seconds left"); return strTrans; } else if ( text.contains("Warning: ", Qt::CaseSensitive) && sscanf(str, "Warning: your password will expire in %d day", &a)) { snprintf(l_str, 1024, _("Warning: your password will expire in %d day"), a); } else if ( text.contains("Warning: ", Qt::CaseSensitive) && sscanf(str, "Warning: your password will expire in %d days", &a)) { snprintf(l_str, 1024, _("Warning: your password will expire in %d days"), a); } else { return _(str); } qDebug() << "l_str = " << l_str; return QString(l_str); } void MainWindow::setMessage(const QString &text, situation situat) { if (situat == ERROR) { QPalette pe; pe.setColor(QPalette::Text, Qt::red); ui->lblMessage->setPalette(pe); // ui->lePassword->setStyleSheet("QLineEdit{background-color: palette(Button);" // "border-radius: 6px;border: 1px solid #F3222D;}"); } else if (situat == TRUE) { QColor color = palette().color(QPalette::Text); QPalette pal(this->palette()); pal.setColor(QPalette::Text, QColor(color)); ui->lblMessage->setPalette(pal); } // qDebug()<<"receive:text = "<setInterval(800); connect(m_timer, &QTimer::timeout, this, &MainWindow::unlock_countdown); } m_timer->start(); } else if (text.indexOf("No password received, please input password") != -1) { ui->lblMessage->setText(tr("Password cannot be empty")); ui->lblMessage->setToolTip(tr("Password cannot be empty")); } else { ui->lblMessage->setText(text); ui->lblMessage->setToolTip(text); } // ui->lblMessage->adjustSize(); // ui->widgetPasswdAuth->adjustSize(); // ui->lblMessage->setText(text); } void MainWindow::setAuthResult(bool result, const QString &text) { QString message = text; if (!result && text.isEmpty()) { message = tr("Authentication failed, please try again."); } if (authMode == PASSWORD) { switchWidget(PASSWORD); setMessage(message, ERROR); } else if (authMode == BIOMETRIC) setMessage(message, ERROR); } void MainWindow::clearEdit() { ui->lePassword->setText(""); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(true); ui->ukeyPassword->setText(""); ui->btnAuth->setDisabled(true); } void MainWindow::switchAuthMode(Mode mode) { if (isbioSuccess) { accept(BIOMETRIC_SUCCESS); return; } int uid = getUid(userName); m_loginOptsWidget->setUser(uid); int count = m_loginOptsWidget->getLoginOptCount(); enableBioAuth = count > 0; if (count < 1) { setLoginTypeTip(tr("Input your password to authentication")); m_loginOptsWidget->hide(); } else { m_loginOptsWidget->show(); m_loginOptsWidget->setEnabled(true); } if (m_loginOptsWidget->getHasUkeyOptions()) { setLoginTypeTip(tr("Input your password to authentication")); m_loginOptsWidget->show(); } switch (mode) { case PASSWORD: { qDebug() << "switch to password"; authMode = mode; if (!enableBioAuth || !receiveBioPAM || useDoubleAuth) { ui->btnBioAuth->hide(); } else { ui->btnBioAuth->show(); } if (isHiddenSwitchButton) { ui->btnBioAuth->hide(); } if (hasSendPassword && authMethod == "otp") { if (checkIsAdmin(userName)) { setLoginTypeTip( tr("Enter the two-factor authentication (2FA) OTP token for the administrator \"%1\"") .arg(userName)); } else { setLoginTypeTip( tr("Enter the two-factor authentication (2FA) OTP dynamic token for the user \"%1\"") .arg(userName)); } ui->cmbUsers->hide(); } else if (hasSendPassword && authMethod == "ukey") { if (checkIsAdmin(userName)) { setLoginTypeTip( tr("Enter the two-factor authentication (2FA) security key for the administrator \"%1\"") .arg(userName)); } else { setLoginTypeTip( tr("Enter the two-factor authentication (2FA) security key for the user \"%1\"").arg(userName)); } ui->cmbUsers->hide(); } } break; case BIOMETRIC: { if (authMode == PASSWORD) { emit accept(BIOMETRIC_IGNORE); isFirstAuth = false; return; } authMode = mode; qDebug() << "switch to biometric"; unlock_countdown(); if (m_deviceInfo) { if (!m_loginOptsWidget->findDeviceById(m_deviceInfo->device_id) || m_loginOptsWidget->isDeviceDisable(m_deviceInfo->device_id)) { m_deviceInfo = DeviceInfoPtr(); } } if (!enableBioAuth) { qDebug() << "It doesn't meet the condition for enabling biometric authentication, switch to password."; emit accept(BIOMETRIC_IGNORE); isFirstAuth = false; return; } else if (authMode == BIOMETRIC) { QString strDeviceName; if (isLoadingUkey) { strDeviceName = m_loginOptsWidget->GetDefaultDevice(uid, UniT_General_Ukey); } else { strDeviceName = m_loginOptsWidget->GetDefaultDevice(uid); } // 如果默认设备为空的话,第一次不启动生物识别认证 if (strDeviceName.isEmpty() && !m_deviceInfo) { qDebug() << "No default device"; emit accept(BIOMETRIC_IGNORE); isFirstAuth = false; return; } // 第一次,获取默认设备的设备信息,之后使用的则是从设备选择窗口传出的设备信息 if (!m_deviceInfo) { m_deviceInfo = m_loginOptsWidget->findDeviceByName(strDeviceName); } if (!m_deviceInfo) { emit accept(BIOMETRIC_IGNORE); isFirstAuth = false; return; } if (m_failMap.contains(uid) && m_failMap[uid].contains(m_deviceInfo->device_id) && m_failMap[uid][m_deviceInfo->device_id] >= maxFailedTimes) { emit accept(BIOMETRIC_IGNORE); isFirstAuth = false; m_deviceInfo = DeviceInfoPtr(); return; } if (m_deviceInfo && m_loginOptsWidget->isDeviceDisable(m_deviceInfo->device_id)) { emit accept(BIOMETRIC_IGNORE); isFirstAuth = false; m_deviceInfo = DeviceInfoPtr(); return; } if (m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { if (isFirstAuth) { isFirstAuth = false; m_deviceInfo = nullptr; emit accept(BIOMETRIC_IGNORE); return; } switchLoginOptType(LOGINOPT_TYPE_GENERAL_UKEY); stopLoadingUkey(); startBioAuth(); m_loginOptsWidget->setCurrentDevice(m_deviceInfo); m_loginOptsWidget->updateUIStatus(false); return; } isFirstAuth = false; switchLoginOptType(m_loginOptsWidget->convertDeviceType(m_deviceInfo->biotype)); startBioAuth(); emit accept(BIOMETRIC_IGNORE); return; } } break; default: break; } switchWidget(mode); } /*** end of public memeber ***/ /*** private member ***/ uid_t MainWindow::getUid(const QString &userName) { struct passwd *pwd = getpwnam(userName.toStdString().c_str()); if (pwd == NULL) { qWarning() << "getpwnam error: " << strerror(errno); return -1; } return pwd->pw_uid; } void MainWindow::setDoubleAuth(bool val) { useDoubleAuth = val; } void MainWindow::stopDoubleAuth() { // if(useDoubleAuth && widgetBioAuth) // widgetBioAuth->stopAuth(); } void MainWindow::switchWidget(Mode mode) { ui->widgetPasswdAuth->hide(); ui->btnAuth->hide(); ui->btnLoading->hide(); ui->btnAuth->setText(tr("Authenticate")); ui->btnBioAuth->setText(tr("Biometric")); ui->btnCancel->setText(tr("Cancel")); ui->returnButton->setText(tr("Use password")); ui->btnLoading->setDisabled(true); if (is_Mavis) { ui->cmbUsers->setFixedHeight(48); ui->lePassword->setFixedHeight(48); ui->ukeyPassword->setFixedHeight(48); ui->btnAuth->setFixedHeight(48); ui->btnCancel->setFixedHeight(48); } else { ui->cmbUsers->setFixedHeight(36); ui->lePassword->setFixedHeight(36); ui->ukeyPassword->setFixedHeight(36); ui->btnAuth->setFixedHeight(36); ui->btnBioAuth->setFixedHeight(36); ui->btnCancel->setFixedHeight(36); ui->returnButton->setFixedHeight(36); } switch (mode) { case PASSWORD: { setFixedWidth(420); if (m_deviceInfo && m_loginOptsWidget->findDeviceById(m_deviceInfo->device_id)) { switchLoginOptType(m_loginOptsWidget->convertDeviceType(m_deviceInfo->biotype)); } else { switchLoginOptType(LOGINOPT_TYPE_PASSWORD); m_loginOptsWidget->setSelectedPassword(); } // 标题+间隔+内容头+间隔+类型提示+间隔+用户列表+间隔+ // (密码输入框+间隔+验证提示+间隔+授权按钮+边距)/ --仅密码方式 // (密码输入框+间隔+验证提示+间隔+登录选项+间隔+授权按钮+边距)/ --密码+生物识别 选择密码 // (登录选项+间隔+授权按钮+边距)/ --密码+生物识别 选择生物识别 // (ukey加载页+间隔+登录选项+间隔+授权按钮+边距)/(ukey认证页+间隔+登录选项+间隔+授权按钮+边距) // --选择Ukey int height = 40 + 8 + ui->lblHeader->height() + 8 + m_labelTip->height() + 8; switch (m_uCurLoginOptType) { case LOGINOPT_TYPE_PASSWORD: { height += ui->cmbUsers->height() + 8 + ui->lePassword->height() + 8 + ui->lblMessage->height() + 8; } break; case LOGINOPT_TYPE_FACE: case LOGINOPT_TYPE_FINGERPRINT: case LOGINOPT_TYPE_FINGERVEIN: case LOGINOPT_TYPE_IRIS: case LOGINOPT_TYPE_VOICEPRINT: case LOGINOPT_TYPE_QRCODE: { height += ui->cmbUsers->height() + 8; } break; case LOGINOPT_TYPE_GENERAL_UKEY: case LOGINOPT_TYPE_ADVANCED_UKEY: { if (!ui->widgetUkeyAuth->isHidden()) { height += ui->widgetUkeyAuth->height() + 8; } else if (!ui->loadingUkeyWidget->isHidden()) { height += ui->loadingUkeyWidget->height() + 8; } } break; default: break; } if (!m_loginOptsWidget->isHidden()) { height += m_loginOptsWidget->height() + 8; } height += ui->btnAuth->height() + 24; setFixedSize(width(), height); qInfo() << "MainWindow geometry:" << geometry() << height; // m_loginOptsWidget->updateUIStatus(); ui->btnBioAuth->setStyleSheet("QPushButton{font-size:14px;}QPushButton:hover{border:none;color:#3E6CE5;}" "QPushButton:pressed{border:none;}"); ui->btnBioAuth->setFlat(true); ui->btnBioAuth->setText(tr("Biometric")); ui->btnBioAuth->setAttribute(Qt::WA_UnderMouse, false); ui->btnBioAuth->adjustSize(); if (m_uCurLoginOptType == LOGINOPT_TYPE_PASSWORD) { ui->widgetPasswdAuth->show(); ui->lePassword->setFocus(); // ui->lePassword->setAttribute(Qt::WA_InputMethodEnabled, false); if (m_modeButton && m_modeButton->isShowPwd()) { ui->lePassword->setEchoMode(QLineEdit::Normal); } else { ui->lePassword->setEchoMode(QLineEdit::Password); } } ui->btnAuth->show(); ui->btnLoading->hide(); if (w_timer && w_timer->isActive()) { w_timer->stop(); } ui->btnCancel->show(); // ui->lblContent->show(); ui->returnButton->hide(); ui->lblContent->hide(); } break; case BIOMETRIC: setFixedWidth(420); ui->btnCancel->hide(); ui->lblContent->hide(); ui->btnBioAuth->hide(); break; default: break; } // adjustSize(); } void MainWindow::unlock_countdown() { int failed_count = 0; int time_left = 0; int deny = 0; int fail_time = 0; int unlock_time = 0; pam_tally_unlock_time_left(getUid(userName), &failed_count, &time_left, &deny, &fail_time, &unlock_time); // qDebug() << "failed_count:" << failed_count << "time_left:" <= 60) // 请多少分钟后重试 { int nMinuteleft = time_left / 60; if (isLockingFlg == false) { m_nCurLockMin = unlock_time / 60; // 获取当前需要锁定的分钟数 } // 如果当前设置的不是1min钟锁定,那么1min显示成2min,由2min直接跳到59s || // 剩余分钟数小于当前设置的锁定时间,并且大于1min,自增+1 if ((nMinuteleft == 1 && m_nCurLockMin != 1) || (nMinuteleft > 1 && nMinuteleft < m_nCurLockMin)) { nMinuteleft = nMinuteleft + 1; } setMessage(tr("Please try again in %1 minutes.").arg(nMinuteleft), ERROR); // ui->lblMessage->setToolTip(tr("Please try again in %1 minutes.").arg(nMinute)); ui->lePassword->setText(""); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(true); ui->btnAuth->setDisabled(true); isLockingFlg = true; setBiometricAuthDisabledStatus(isLockingFlg); return; } else if (time_left > 0 && time_left < 60) // 请多少秒后重试 { char ch[100] = { 0 }; setMessage(tr("Please try again in %1 seconds.").arg(time_left % 60), ERROR); // ui->lblMessage->setToolTip(tr("Please try again in %1 seconds.").arg(time_left%60)); ui->lePassword->setText(""); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(true); ui->btnAuth->setDisabled(true); isLockingFlg = true; setBiometricAuthDisabledStatus(isLockingFlg); return; } else if (failed_count == 0xFFFF) // 账号被永久锁定 { ui->lblMessage->setText(tr("Account locked permanently.")); ui->lblMessage->setToolTip(tr("Account locked permanently.")); ui->lePassword->setText(""); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(true); ui->btnAuth->setDisabled(true); isLockingFlg = true; setBiometricAuthDisabledStatus(isLockingFlg); return; } else { if (ui->lePassword) { ui->lePassword->setDisabled(false); ui->lePassword->setReadOnly(false); ui->lePassword->setFocus(); } if (ui->btnAuth) { ui->btnAuth->setDisabled(false); } if (isLockingFlg) { // setMessage(tr("Authentication failed, please try again."),ERROR); setMessage(""); isLockingFlg = false; setBiometricAuthDisabledStatus(isLockingFlg); } if (m_timer) { m_timer->stop(); } } return; } void MainWindow::root_unlock_countdown() { int failed_count = 0; int time_left = 0; int deny = 0; int fail_time = 0; int unlock_time = 0; pam_tally_root_unlock_time_left(&failed_count, &time_left, &deny, &fail_time, &unlock_time); // qDebug() << "failed_count:" << failed_count << "time_left:" <= 60) // 请多少分钟后重试 { int nMinuteleft = time_left / 60; if (isLockingFlg == false) { m_nCurLockMin = unlock_time / 60; // 获取当前需要锁定的分钟数 } // 如果当前设置的不是1min钟锁定,那么1min显示成2min,由2min直接跳到59s || // 剩余分钟数小于当前设置的锁定时间,并且大于1min,自增+1 if ((nMinuteleft == 1 && m_nCurLockMin != 1) || (nMinuteleft > 1 && nMinuteleft < m_nCurLockMin)) { nMinuteleft = nMinuteleft + 1; } ui->lblMessage->setText(tr("Please try again in %1 minutes.").arg(nMinuteleft)); ui->lblMessage->setToolTip(tr("Please try again in %1 minutes.").arg(nMinuteleft)); ui->lePassword->setText(""); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(true); ui->btnAuth->setDisabled(true); isLockingFlg = true; setBiometricAuthDisabledStatus(isLockingFlg); return; } else if (time_left > 0 && time_left < 60) // 请多少秒后重试 { char ch[100] = { 0 }; ui->lblMessage->setText(tr("Please try again in %1 seconds.").arg(time_left % 60)); ui->lblMessage->setToolTip(tr("Please try again in %1 seconds.").arg(time_left % 60)); ui->lePassword->setText(""); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(true); ui->btnAuth->setDisabled(true); isLockingFlg = true; setBiometricAuthDisabledStatus(isLockingFlg); return; } else if (failed_count == 0xFFFF) // 账号被永久锁定 { ui->lblMessage->setText(tr("Account locked permanently.")); ui->lblMessage->setToolTip(tr("Account locked permanently.")); ui->lePassword->setText(""); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(false); ui->btnAuth->setDisabled(true); isLockingFlg = true; setBiometricAuthDisabledStatus(isLockingFlg); return; } else { if (ui->lePassword) { ui->lePassword->setDisabled(false); ui->lePassword->setReadOnly(false); ui->lePassword->setFocus(); } if (ui->btnAuth) { ui->btnAuth->setDisabled(false); } if (isLockingFlg) { // setMessage(tr("Authentication failed, please try again."),ERROR); setMessage(""); isLockingFlg = false; setBiometricAuthDisabledStatus(isLockingFlg); } m_timer->stop(); } return; } void MainWindow::setBiometricAuthDisabledStatus(bool locked) { if (locked) { if (m_loginOptsWidget) { m_loginOptsWidget->stopAuth(); m_loginOptsWidget->setAllDeviceDisable(true); if (m_bioTimer && m_bioTimer->isActive()) m_bioTimer->stop(); } if (m_deviceInfo && m_deviceInfo->biotype == BIOTYPE_FACE) { QImage imgFailed; m_loginOptsWidget->setFaceImg(imgFailed, 1); } else if (m_deviceInfo && m_deviceInfo->biotype == REMOTE_QRCODE_TYPE) { QImage nullImage; m_loginOptsWidget->setQRCode(nullImage); } } else { if (m_loginOptsWidget) { if (m_deviceInfo) { m_loginOptsWidget->startAuth(m_deviceInfo, getUid(userName)); } m_loginOptsWidget->setAllDeviceDisable(false); } } } void MainWindow::onRespondUkey(const QString &text) { if (m_loginOptsWidget) { m_loginOptsWidget->SetExtraInfo(text, "pincode"); } } void MainWindow::switchLoginOptType(unsigned uLoginOptType) { switch (uLoginOptType) { case LOGINOPT_TYPE_PASSWORD: { // m_loginOptsWidget->hide(); ui->lePassword->show(); ui->cmbUsers->show(); ui->widgetPasswdAuth->show(); ui->widgetUkeyAuth->hide(); ui->ukeyPassword->clearFocus(); ui->loadingUkeyWidget->hide(); setFocusProxy(ui->lePassword); ui->cmbUsers->show(); if (hasSendPassword && (authMethod == "ukey" || authMethod == "otp")) { ui->cmbUsers->hide(); } m_loginOptsWidget->stopBioWaiting(); } break; case LOGINOPT_TYPE_FACE: case LOGINOPT_TYPE_FINGERPRINT: case LOGINOPT_TYPE_IRIS: case LOGINOPT_TYPE_VOICEPRINT: case LOGINOPT_TYPE_FINGERVEIN: case LOGINOPT_TYPE_QRCODE: { switch (uLoginOptType) { case LOGINOPT_TYPE_FINGERPRINT: case LOGINOPT_TYPE_IRIS: case LOGINOPT_TYPE_VOICEPRINT: case LOGINOPT_TYPE_FINGERVEIN: { m_loginOptsWidget->startBioWaiting(uLoginOptType); } break; default: m_loginOptsWidget->stopBioWaiting(); break; } // 延迟检查错误状态 m_isNetworkErr = false; QTimer::singleShot(500, this, [&, this]() { if (!this->m_isNetworkErr) { m_loginOptsWidget->setQRCodeMsg(""); } }); ui->lePassword->show(); ui->widgetUkeyAuth->hide(); ui->loadingUkeyWidget->hide(); ui->ukeyPassword->clearFocus(); setFocusProxy(ui->lePassword); ui->cmbUsers->show(); ui->widgetPasswdAuth->hide(); } break; case LOGINOPT_TYPE_GENERAL_UKEY: { ui->lePassword->hide(); ui->cmbUsers->hide(); if (m_deviceInfo) { stopLoadingUkey(); ui->widgetUkeyAuth->show(); } else { startLoadingUkey(); } setFocusProxy(ui->ukeyPassword); ui->ukeyPassword->setFocusPolicy(Qt::StrongFocus); ui->ukeyPassword->setFocus(); ui->widgetPasswdAuth->hide(); m_loginOptsWidget->stopBioWaiting(); } break; default: return; } qDebug() << "CurOptType:" << uLoginOptType; if (m_deviceInfo && m_failMap.contains(getUid(userName)) && m_failMap[getUid(userName)].contains(m_deviceInfo->device_id) && m_failMap[getUid(userName)][m_deviceInfo->device_id] >= maxFailedTimes) { if (m_deviceInfo->biotype == BIOTYPE_FACE) { QImage imgFailed; m_loginOptsWidget->setFaceImg(imgFailed, 1); } no_changes = true; if (m_deviceInfo->biotype == REMOTE_QRCODE_TYPE) { setLoginTypeTip(tr("Failed to verify %1, please enter password to unlock") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype))); } else if (m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { setUkeyTypeTip(tr("Failed to verify %1, please enter password to unlock") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype))); } else { setLoginTypeTip(tr("Unable to verify %1, please enter password to unlock") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype))); m_loginOptsWidget->stopBioWaiting(true); } m_loginOptsWidget->setDeviceDisable(m_deviceInfo->device_id, true); } else { no_changes = false; if (uLoginOptType != m_uCurLoginOptType || (m_deviceInfo && m_deviceInfo->device_id != m_nLastDeviceId)) { switch (uLoginOptType) { case LOGINOPT_TYPE_PASSWORD: { setLoginTypeTip(tr("Input your password to authentication")); } break; case LOGINOPT_TYPE_FACE: { setLoginTypeTip(tr("Facial recognition to authorization")); } break; case LOGINOPT_TYPE_FINGERPRINT: { setLoginTypeTip(tr("Fingerprint recognition to authorization")); } break; case LOGINOPT_TYPE_VOICEPRINT: { setLoginTypeTip(tr("Voiceprint recognition to authorization")); } break; case LOGINOPT_TYPE_FINGERVEIN: { setLoginTypeTip(tr("Finger veins recognition to authorization")); } break; case LOGINOPT_TYPE_IRIS: { setLoginTypeTip(tr("Iris recognition to authorization")); } break; case LOGINOPT_TYPE_QRCODE: { QString strDrivName = tr("wechat"); if (m_deviceInfo && m_deviceInfo->device_shortname != "wechat_driver") { strDrivName = m_deviceInfo->device_shortname; } setLoginTypeTip(tr("Use the bound %1 scanning code to authorization").arg(strDrivName)); } break; case LOGINOPT_TYPE_GENERAL_UKEY: { setLoginTypeTip(""); } break; default: return; } } } if (m_deviceInfo) { m_nLastDeviceId = m_deviceInfo->device_id; } else { m_nLastDeviceId = -1; } m_uCurLoginOptType = uLoginOptType; m_loginOptsWidget->updateUIStatus(true, m_uCurLoginOptType); } void MainWindow::setLoginTypeTip(QString strLoginTypeTip) { m_strLoginTypeTip = strLoginTypeTip; if (m_strLoginTypeTip.isEmpty()) { m_labelTip->hide(); } else { QPalette pe; if (no_changes) { pe.setColor(QPalette::Text, Qt::red); m_labelTip->setPalette(pe); } else { QColor color = palette().color(QPalette::Text); QPalette pal(this->palette()); pal.setColor(QPalette::Text, QColor(color)); m_labelTip->setPalette(pal); } m_labelTip->setText(m_strLoginTypeTip); m_labelTip->show(); } } void MainWindow::startBioAuthDelay() { if (m_deviceInfo) { if (m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { } else { m_loginOptsWidget->startAuth(m_deviceInfo, getUid(userName)); } switchLoginOptType(m_loginOptsWidget->convertDeviceType(m_deviceInfo->biotype)); } else { switchLoginOptType(LOGINOPT_TYPE_PASSWORD); } m_bioTimer->stop(); } void MainWindow::startBioAuth(unsigned uTimeout) { m_loginOptsWidget->stopAuth(); if (m_deviceInfo && m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { switchLoginOptType(m_loginOptsWidget->convertDeviceType(m_deviceInfo->biotype)); } if (!m_bioTimer) { m_bioTimer = new QTimer(this); connect(m_bioTimer, SIGNAL(timeout()), this, SLOT(startBioAuthDelay())); } ui->lblMessage->clear(); ui->lblMessage->setToolTip(""); m_bioTimer->start(uTimeout); } void MainWindow::onUpdateBioAuthMsg(QString strMsg) { setMessage(strMsg, TRUE); } void MainWindow::updatePixmap() { ui->btnAuth->hide(); ui->btnAuth->setDisabled(true); ui->btnLoading->show(); ui->lePassword->setDisabled(true); ui->lePassword->setReadOnly(true); QMatrix matrix; matrix.rotate(90.0); m_waitingPixmap = QtPixmapCompat::transformedPixmap(m_waitingPixmap, matrix, Qt::FastTransformation); ui->btnLoading->setIcon(m_waitingPixmap); } void MainWindow::onUpdateWndSize(unsigned uLoginOptType, unsigned uLoginOptSize) { ui->lblContent->hide(); ui->lblHeader->adjustSize(); // 标题+间隔+内容头+间隔+类型提示+间隔+用户列表+间隔+ // (密码输入框+间隔+验证提示+间隔+授权按钮+边距)/ --仅密码方式 // (密码输入框+间隔+验证提示+间隔+登录选项+间隔+授权按钮+边距)/ --密码+生物识别 选择密码 // (登录选项+间隔+授权按钮+边距)/ --密码+生物识别 选择生物识别 // (ukey加载页+间隔+登录选项+间隔+授权按钮+边距)/(ukey认证页+间隔+登录选项+间隔+授权按钮+边距) // --选择Ukey int height = 40 + 8 + ui->lblHeader->height() + 8 + m_labelTip->height() + 8; switch (m_uCurLoginOptType) { case LOGINOPT_TYPE_PASSWORD: { height += ui->cmbUsers->height() + 8 + ui->lePassword->height() + 8 + ui->lblMessage->height() + 8; } break; case LOGINOPT_TYPE_FACE: case LOGINOPT_TYPE_FINGERPRINT: case LOGINOPT_TYPE_FINGERVEIN: case LOGINOPT_TYPE_IRIS: case LOGINOPT_TYPE_VOICEPRINT: case LOGINOPT_TYPE_QRCODE: { height += ui->cmbUsers->height() + 8; } break; case LOGINOPT_TYPE_GENERAL_UKEY: case LOGINOPT_TYPE_ADVANCED_UKEY: { if (!ui->widgetUkeyAuth->isHidden()) { height += ui->widgetUkeyAuth->height() + 8; } else if (!ui->loadingUkeyWidget->isHidden()) { height += ui->loadingUkeyWidget->height() + 8; } } break; default: break; } if (!m_loginOptsWidget->isHidden()) { height += m_loginOptsWidget->height() + 8; } height += ui->btnAuth->height() + 24; setFixedSize(width(), height); qInfo() << "MainWindow geometry update:" << geometry() << height; } void MainWindow::setEditInputMethod(bool bEnable) { qDebug() << "setEditInputMethod:" << bEnable; if (bEnable) { ui->lePassword->setAttribute(Qt::WA_InputMethodEnabled, true); } else { ui->lePassword->setAttribute(Qt::WA_InputMethodEnabled, false); } } void MainWindow::setCurProject(bool isMavis) { is_Mavis = isMavis; } void MainWindow::onOptionSelected(unsigned uCurLoginOptType, const DeviceInfoPtr &deviceInfo) { isLoadingUkey = false; if (uCurLoginOptType == LOGINOPT_TYPE_GENERAL_UKEY) { stopLoadingUkey(); } if (uCurLoginOptType == LOGINOPT_TYPE_PASSWORD) { switchLoginOptType(uCurLoginOptType); if (m_loginOptsWidget) { m_loginOptsWidget->stopAuth(); } m_deviceInfo = nullptr; authMode = PASSWORD; emit restartAuth(); return; } if (uCurLoginOptType != LOGINOPT_TYPE_GENERAL_UKEY && !deviceInfo) return; if (deviceInfo) qDebug() << "device changed: " << deviceInfo->biotype; if (deviceInfo && m_failMap[getUid(userName)][deviceInfo->device_id] >= maxFailedTimes) { qDebug() << "Failed MAX!!"; return; } if (uCurLoginOptType == LOGINOPT_TYPE_GENERAL_UKEY && !deviceInfo) { isLoadingUkey = true; startLoadingUkey(); m_loginOptsWidget->updateUkeyUIStatus(LOGINOPT_TYPE_GENERAL_UKEY); } else if (uCurLoginOptType == LOGINOPT_TYPE_GENERAL_UKEY && deviceInfo) { stopLoadingUkey(); m_loginOptsWidget->updateUkeyUIStatus(LOGINOPT_TYPE_GENERAL_UKEY); } if (deviceInfo == m_deviceInfo) { return; } if (uCurLoginOptType != LOGINOPT_TYPE_GENERAL_UKEY && deviceInfo == m_deviceInfo) { return; } if (m_bioTimer) m_bioTimer->stop(); m_deviceInfo = deviceInfo; switchLoginOptType(uCurLoginOptType); if (!isbioSuccess && m_deviceInfo) { startBioAuth(); } } void MainWindow::onNotifyOptionsChanged(unsigned uOptionsCount) { if (uOptionsCount > 0) { m_loginOptsWidget->show(); } else { // m_loginOptsWidget->hide(); } if (m_deviceInfo && m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { stopLoadingUkey(); } if (!m_deviceInfo || !m_loginOptsWidget->findDeviceById(m_deviceInfo->device_id) || m_loginOptsWidget->isDeviceDisable(m_deviceInfo->device_id)) { m_loginOptsWidget->stopAuth(); if (authMode != UNDEFINED) { authMode = UNDEFINED; emit switchToBiometric(); } } } void MainWindow::onLoginOptionsAuthCompleted(uid_t uid, bool ret, int nStatus) { qDebug() << "biometric authentication complete: " << uid << ret << nStatus; if (m_deviceInfo && m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY && ui->widgetUkeyAuth->isVisible()) { ui->ukeyPassword->setText(""); } if (uid == getUid(userName) && ret) { isbioSuccess = true; emit switchToBiometric(); authMode = UNDEFINED; } else { if (nStatus == 5 && m_deviceInfo) { if (w_timer && w_timer->isActive()) w_timer->stop(); QImage imgFailed; m_loginOptsWidget->setFaceImg(imgFailed, 2); return; } else if (nStatus >= 2 && nStatus != 5) if (nStatus >= 2) { if (m_deviceInfo) { uid_t curUid = getUid(userName); if (m_failMap.contains(curUid) && m_failMap[curUid].contains(m_deviceInfo->device_id)) { m_failMap[curUid][m_deviceInfo->device_id] = m_failMap[curUid][m_deviceInfo->device_id] + 1; } else { m_failMap[curUid][m_deviceInfo->device_id] = 1; } qDebug() << "Failed count:" << m_failMap[curUid][m_deviceInfo->device_id] << ",Max:" << maxFailedTimes; if (m_deviceInfo->biotype == BIOTYPE_FACE) { QImage imgFailed; m_loginOptsWidget->setFaceImg(imgFailed, 1); } if (m_failMap[curUid][m_deviceInfo->device_id] >= maxFailedTimes) { no_changes = true; if (m_deviceInfo->biotype == REMOTE_QRCODE_TYPE) { setLoginTypeTip(tr("Failed to verify %1, please enter password to unlock") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype))); QImage nullImage; m_loginOptsWidget->setQRCode(nullImage); } else if (m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { ui->ukeyPassword->setReadOnly(true); setUkeyTypeTip(tr("Unable to verify %1, please enter password to unlock") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype))); } else { setLoginTypeTip(tr("Unable to verify %1, please enter password to unlock") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype))); m_loginOptsWidget->stopBioWaiting(true); } m_loginOptsWidget->setDeviceDisable(m_deviceInfo->device_id, true); useDoubleAuth = false; return; } no_changes = false; if (m_deviceInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { setUkeyTypeTip(tr("Failed to verify %1, you still have %2 verification opportunities") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype)) .arg(maxFailedTimes - m_failMap[curUid][m_deviceInfo->device_id])); } else { setLoginTypeTip(tr("Failed to verify %1, you still have %2 verification opportunities") .arg(BioDevices::bioTypeToString_tr(m_deviceInfo->biotype)) .arg(maxFailedTimes - m_failMap[curUid][m_deviceInfo->device_id])); } } } if (!isbioSuccess) { // dbus error if (nStatus == -1) { qDebug() << "Biometric dbus error:" << authMode; } if (m_uCurLoginOptType == LOGINOPT_TYPE_QRCODE && nStatus == 1) { m_isNetworkErr = true; m_loginOptsWidget->setQRCodeMsg(tr("Abnormal network")); startBioAuth(10000); } else if (m_uCurLoginOptType == LOGINOPT_TYPE_QRCODE && nStatus == -4) { m_isNetworkErr = true; m_loginOptsWidget->setQRCodeMsg(tr("Acquisition failure")); startBioAuth(10000); } else { startBioAuth(); } if (nStatus >= 2 && m_deviceInfo) { if (m_deviceInfo->biotype == BIOTYPE_FACE) { QImage imgFailed; m_loginOptsWidget->setFaceImg(imgFailed, 1); } } } } } void MainWindow::updateAuthMethod() { authMethod = getAuthMethod(); } QString MainWindow::getAuthMethod() { QDBusInterface interface( "com.kylin.pwdless.daemon", "/", "com.kylin.pwdless.daemon", QDBusConnection::systemBus(), this); if (!interface.isValid()) { return ""; } QDBusMessage result = interface.call(QStringLiteral("mfaStatus")); if (result.type() == QDBusMessage::ErrorMessage) { qWarning() << "mfaStatus error:" << result.errorMessage(); return ""; } int ret = result.arguments().at(0).toInt(); QString method = result.arguments().at(1).toString(); if (ret == 0) return ""; else return method; } void MainWindow::resetSendPassword() { hasSendPassword = false; } bool MainWindow::checkIsAdmin(QString userName) { int ngroups = 512; struct passwd *pw; struct group *gr; gid_t groups[512]; pw = getpwnam(userName.toLocal8Bit().data()); if (pw == NULL) { qDebug() << userName << "is not exists"; return false; } if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups) == -1) { qDebug() << userName << "get group failed"; return false; } for (size_t j = 0; j < ngroups; j++) { gr = getgrgid(groups[j]); if (gr != NULL) { if (strcmp("sudo", gr->gr_name) == 0) return true; } } return false; } /*** end of private member ***/ ukui-biometric-auth/polkit-agent/src/types.h0000664000175000017500000000406215167732630020105 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef TYPES_H #define TYPES_H /* https://www.narf.ssji.net/~shtrom/wiki/projets/gnomescreensavernosession */ enum SessionStatus { SESSION_AVAILABLE = 0, SESSION_INVISIBLE = 1, SESSION_BUSY = 2, SESSION_IDLE = 3 }; enum ScreenStatus { UNDEFINED = 0x00, SCREEN_SAVER = 0x01, SCREEN_LOCK = 0x02 }; #define SM_DBUS_SERVICE "org.gnome.SessionManager" #define SM_DBUS_PATH "/org/gnome/SessionManager/Presence" #define SM_DBUS_INTERFACE "org.gnome.SessionManager.Presence" #define DM_DBUS_SERVICE "org.freedesktop.DisplayManager" #define DM_DBUS_PATH "/org/freedesktop/DisplayManager" #define DM_DBUS_INTERFACE "org.freedesktop.DisplayManager" #define DM_SEAT_INTERFACE "org.freedesktop.DisplayManager.Seat" #define ACT_DBUS_SERVICE "org.freedesktop.Accounts" #define ACT_DBUS_PATH "/org/freedesktop/Accounts" #define ACT_DBUS_INTERFACE "org.freedesktop.Accounts" #define ACT_USER_INTERFACE "org.freedesktop.Accounts.User" #define DBUS_PROP_INTERFACE "org.freedesktop.DBus.Properties" #define SS_DBUS_SERVICE "org.ukui.ScreenSaver" #define SS_DBUS_PATH "/" #define SS_DBUS_INTERFACE "org.ukui.ScreenSaver" #define BIO_ERROR -1 #define BIO_FAILED 0 #define BIO_SUCCESS 1 #define BIO_IGNORE 2 #define BIOMETRIC_PAM "BIOMETRIC_PAM" #define BIOMETRIC_IGNORE "BIOMETRIC_IGNORE" #define BIOMETRIC_SUCCESS "BIOMETRIC_SUCCESS" #define BIOMETRIC_FAILED "BIOMETRIC_FAILED" #endif // TYPES_H ukui-biometric-auth/polkit-agent/src/kalabel.h0000664000175000017500000000213515167732630020333 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef KALABEL_H #define KALABEL_H #include class KALabel : public QLabel { Q_OBJECT public: KALabel(QWidget *parent = nullptr); KALabel(QString strText, QWidget *parent = nullptr); QString getElidedText(QFont font, int width, QString strInfo); public slots: void setText(const QString &); protected: void paintEvent(QPaintEvent *event); private: QString m_strText; }; #endif // KALABEL_H ukui-biometric-auth/polkit-agent/src/modeButton.cpp0000664000175000017500000001154315167732630021416 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "modeButton.h" #include #include #include #include #include ModeButton::ModeButton(QWidget *parent) : QPushButton(parent) { m_strIcon = ""; m_strText = ""; this->setFlat(true); initUI(); initStyleTheme(); } ModeButton::ModeButton(QString strIcon, QWidget *parent) : QPushButton(parent) { m_strIcon = strIcon; this->setFlat(true); initUI(); initStyleTheme(); } ModeButton::~ModeButton() { if (m_styleSettings) { delete m_styleSettings; m_styleSettings = nullptr; } } void ModeButton::initUI() { installEventFilter(this); setModeIcon(); setFixedSize(QSize(24, 24)); setModeIcon(); setCursor(Qt::ArrowCursor); setStyleSheet("QPushButton::pressed{border:none;background-color:transparent}" "QPushButton::hover::!pressed{border:none;background-color:transparent}"); connect(this, &QPushButton::clicked, this, [=](){ if (!pwdShow) { pwdShow = true; setModeIcon(); } else { pwdShow = false; setModeIcon(); } }); } void ModeButton::initStyleTheme() { const QByteArray idd("org.ukui.style"); if(QGSettings::isSchemaInstalled(idd)) { m_styleSettings = new QGSettings(idd); } if (m_styleSettings) { connect(m_styleSettings, &QGSettings::changed, this, [=](const QString &key) { if (key == "styleName") { auto styleNameValue = m_styleSettings->get("styleName"); if (styleNameValue.isValid()) { m_strThemeName = styleNameValue.toString(); setModeIcon(); } } }); auto styleNameValue = m_styleSettings->get("styleName"); if (styleNameValue.isValid()) { m_strThemeName = styleNameValue.toString(); } } } void ModeButton::setModeIcon() { QIcon icon; QPixmap pixmap; if(pwdShow){ icon = QIcon::fromTheme("ukui-eye-display-symbolic"); pixmap = icon.pixmap(QSize(24,24)); } else{ icon = QIcon::fromTheme("ukui-eye-hidden-symbolic"); pixmap = icon.pixmap(QSize(24,24)); } if(m_isHover) pixmap = drawSymbolicColoredPixmap(pixmap, "white"); else pixmap = drawSymbolicColoredPixmap(pixmap, "gray"); if(m_strThemeName == "ukui-dark" || m_strThemeName == "ukui-black") this->setIcon(pixmap); else this->setIcon(icon); } bool ModeButton::eventFilter(QObject *obj, QEvent *event) { if(obj == this){ if(event->type() == QEvent::Enter){ m_isHover = true; setModeIcon(); } else if(event->type() == QEvent::Leave){ m_isHover = false; setModeIcon(); } } return QPushButton::eventFilter(obj, event); } QPixmap ModeButton::drawSymbolicColoredPixmap(QPixmap &source, QString cgColor) { QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if ( "white" == cgColor) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else if( "black" == cgColor) { color.setRed(0); color.setGreen(0); color.setBlue(0); img.setPixelColor(x, y, color); } else if ("gray"== cgColor) { color.setRed(152); color.setGreen(163); color.setBlue(164); img.setPixelColor(x, y, color); } else if ("blue" == cgColor){ color.setRed(61); color.setGreen(107); color.setBlue(229); img.setPixelColor(x, y, color); } else { return source; } } } } return QPixmap::fromImage(img); } bool ModeButton::isShowPwd() { return pwdShow; } ukui-biometric-auth/polkit-agent/src/PolkitAgent.cpp0000664000175000017500000000473615167732644021532 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include "PolkitListener.h" #include "generic.h" #include "sessionmanager.h" #include "biodevices.h" #include bool enableDebug; QString logPrefix; int main(int argc, char *argv[]) { enableDebug = true; logPrefix = "[ukui-polkit]:"; //qInstallMessageHandler(outputMessage); initUkuiLog4qt("ukui-polkit"); qDebug() << "Polkit Agent Started"; #if(QT_VERSION>=QT_VERSION_CHECK(5,6,0)) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); #endif QApplication agent(argc, argv); QString locale = QLocale::system().name(); qDebug() << "Language: " <. * **/ #include "pam-tally.h" #include #include #include #include #include #include #include #include #include #include char shm_tally_real[128]; #define FILE_MODE (S_IRUSR | S_IWUSR) #define CONFIG_FILE "/usr/share/lightdm/lightdm.conf.d/96-kylin-setting.conf" struct tallylog { char fail_line[52]; /* rhost or tty of last failure */ uint16_t reserved; /* reserved for future use */ uint16_t fail_cnt; /* failures since last success */ uint64_t fail_time; /* time of last failure */ }; static int get_is_open_other_authentication() { char buf[128]; FILE *config_file; if( (config_file = fopen(CONFIG_FILE, "r")) == NULL) { return 0; } int open_other_authentication = 0; while(fgets(buf, sizeof(buf), config_file)) { if(strnlen(buf,1024) == 0 || buf[0] == '#') { memset(buf, sizeof(buf), 0); continue; } if(buf[strnlen(buf,1024)-1] == '\n') buf[strnlen(buf,1024)-1] = '\0'; char *p = strchr(buf, '='); if(!p) continue; *p = '\0'; size_t len = strnlen(buf,1024); if(len == 0) continue; //去掉=之前的空格 while(len--) if(buf[len] == ' ' || buf[len] == '\t') buf[len] = '\0'; if(strcmp(buf, "open-other-authentication") != 0) continue; p++; len = strnlen(p,1024); if(len == 0) break; //去掉等号之后的空格 while(*p == ' ' || *p == '\t') { p++; len--; } //去掉尾部空格 while(len--) if(*(p+len) == ' ' || *(p+len) == '\t') *(p+len) = '\0'; if(*p == '0') break; if(*p == '1') { open_other_authentication = 1; break; } } fclose(config_file); return open_other_authentication; } static int get_pam_tally(int *deny, int *unlock_time , int *root_unlock_time) { char buf[128]; FILE *auth_file = NULL; if( (auth_file = fopen("/etc/pam.d/common-auth", "r")) == NULL) return -1; while(fgets(buf, sizeof(buf), auth_file)) { if(strnlen(buf,1024) == 0 || buf[0] == '#') continue; if(!strstr(buf, "deny")) continue; char *ptr = strtok(buf, " \t"); while(ptr) { if(strncmp(ptr, "deny=", 5)==0){ sscanf(ptr, "deny=%d", deny); } if(strncmp(ptr, "unlock_time=", 12)==0){ sscanf(ptr, "unlock_time=%d", unlock_time); } if(strncmp(ptr, "root_unlock_time=", 17)==0){ sscanf(ptr, "root_unlock_time=%d", root_unlock_time); } ptr = strtok(NULL, " \t"); } fclose(auth_file); auth_file = NULL; return 1; } fclose(auth_file); auth_file = NULL; return 0; } static void set_shm_tally_real() { snprintf(shm_tally_real, sizeof(shm_tally_real), "%s_%d", SHM_TALLY, getuid()); } int pam_tally_init() { int fd; int deny = 0, unlock_time = 0 , root_unlock_time = 0; pam_tally *tally_ptr; set_shm_tally_real(); printf("shm path : %s\n", shm_tally_real); shm_unlink(shm_tally_real); if(get_is_open_other_authentication()) { return 0; } if(!get_pam_tally(&deny, &unlock_time,&root_unlock_time)) { return 0; } if(deny <= 0) deny = 0; if(unlock_time <= 0) unlock_time = 0; if( (fd = shm_open(shm_tally_real, O_RDWR | O_CREAT, FILE_MODE)) == -1) { printf("shm_open error: %s\n", strerror(errno)); return -1; } ftruncate(fd, sizeof(pam_tally)); if( (tally_ptr = mmap(NULL, sizeof(pam_tally), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { close(fd); return -1; } close(fd); tally_ptr->deny = deny; tally_ptr->unlock_time = unlock_time; tally_ptr->failed = 0; tally_ptr->lock_start_time = 0; tally_ptr->root_unlock_time = root_unlock_time; return 1; } static pam_tally* pam_tally_memory() { int fd; pam_tally *tally_ptr; set_shm_tally_real(); if( (fd = shm_open(shm_tally_real, O_RDWR, FILE_MODE)) == -1) { return NULL; } if( (tally_ptr = mmap(NULL, sizeof(pam_tally), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { close(fd); return NULL; } close(fd); return tally_ptr; } int pam_tally_is_enbled() { int fd; set_shm_tally_real(); if( (fd = shm_open(shm_tally_real, O_RDONLY, FILE_MODE)) == -1) { printf("shm_open error: %s\n", strerror(errno)); close(fd); return 0; } pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL){ close(fd); return -1; } if(tally_ptr->deny == 0 || tally_ptr->unlock_time == 0){ close(fd); return 0; } close(fd); return 1; } int pam_tally_add_failed() { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return -1; tally_ptr->failed++; //如果失败次数达到上限,开始计时 if(tally_ptr->failed >= tally_ptr->deny) tally_ptr->lock_start_time = time(NULL); return 0; } int pam_tally_clear_failed() { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return -1; tally_ptr->failed = 0; tally_ptr->lock_start_time = 0; return 0; } int pam_tally_failure_is_out() { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return -1; return (tally_ptr->failed >= tally_ptr->deny ? 1 : 0); } int pam_tally_deny() { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return -1; return tally_ptr->deny; } int pam_tally_failed_count() { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return -1; return tally_ptr->failed; } int pam_tally_unlock_time() { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return -1; printf("unlock time = %d\n", tally_ptr->unlock_time); return tally_ptr->unlock_time; } int pam_tally_is_canUnlock() { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return -1; if(tally_ptr->failed >= tally_ptr->deny && time(NULL) - tally_ptr->lock_start_time < tally_ptr->unlock_time) return 0; return 1; } int pam_modutil_read(int fd, char *buffer, int count) { int block, offset = 0; while (count > 0) { block = read(fd, &buffer[offset], count); if (block < 0) { if (errno == EINTR) continue; return block; } if (block == 0) return offset; offset += block; count -= block; } return offset; } void get_tally(uid_t uid, int *tfile, struct tallylog *tally) { char filename[50]={0}; snprintf(filename, sizeof(filename), "/tmp/.tallylog.d/.%d", uid); void *void_tally = tally; if ((*tfile = open(filename, O_RDONLY)) == -1){ snprintf(filename, sizeof(filename), "/tmp/.tallylog"); if ((*tfile = open(filename, O_RDONLY)) == -1){ fprintf(stderr, "open tallylog failed \n"); return ; } } if (lseek(*tfile, (off_t)uid*(off_t)sizeof(*tally), SEEK_SET) == (off_t)-1) { fprintf(stderr, "lseek tallylog failed \n"); close(*tfile); return ; } if (pam_modutil_read(*tfile, void_tally, sizeof(*tally)) != sizeof(*tally)) { fprintf(stderr, "read tallylog failed \n"); memset(tally, 0, sizeof(*tally)); } close(*tfile); tally->fail_line[sizeof(tally->fail_line)-1] = '\0'; } int pam_tally_unlock_time_left(int uid, int *fail_cnt,int *left_time, int *deny, int *fail_time, int *unlock_time1) { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL) return 0; int unlock_time = tally_ptr->unlock_time; *deny = tally_ptr->deny; if(unlock_time == 0) return 0; int tfile = -1; struct tallylog tally; tally.reserved = 0; tally.fail_cnt = 0; tally.fail_time = 0; get_tally(uid,&tfile,&tally); if(tally.fail_cnt<*deny) return 0; //连续输错,时间累加 if (tally.fail_cnt >= (*deny)*2 && tally.fail_cnt < (*deny)*3){ unlock_time = unlock_time*2; } else if(tally.fail_cnt >= (*deny)*3 && tally.fail_cnt < (*deny)*4){ unlock_time = unlock_time*8; } else if (tally.fail_cnt >= (*deny)*4){ *fail_cnt = 0xFFFF;//永久锁定 return 0; } int unlock_time_left = unlock_time - ((long)time(NULL) - tally.fail_time); *fail_time = tally.fail_time; *unlock_time1 = unlock_time; *left_time = unlock_time_left > 0 ? unlock_time_left : 0; *fail_cnt = tally.fail_cnt; return *left_time; } int pam_tally_root_unlock_time_left(int *fail_cnt,int *left_time, int *deny1, int *fail_time, int *unlock_time1) { pam_tally *tally_ptr; if((tally_ptr = pam_tally_memory()) == NULL){ return 0; } int root_unlock_time = tally_ptr->root_unlock_time; int deny = tally_ptr->deny; if(root_unlock_time == 0) return 0; int tfile = -1; uid_t uid = getuid(); struct tallylog tally; tally.reserved = 0; tally.fail_cnt = 0; tally.fail_time = 0; get_tally(uid,&tfile,&tally); if(tally.fail_cnt= (deny)*2 && tally.fail_cnt < (deny)*3){ root_unlock_time = root_unlock_time*2; } else if(tally.fail_cnt >= (deny)*3 && tally.fail_cnt < (deny)*4){ root_unlock_time = root_unlock_time*8; } else if (tally.fail_cnt >= (deny)*4){ *fail_cnt = 0xFFFF;//永久锁定 return 0; } int root_unlock_time_left = root_unlock_time - ((long)time(NULL) - tally.fail_time); *fail_time = tally.fail_time; *unlock_time1 = root_unlock_time; *left_time = root_unlock_time_left > 0 ? root_unlock_time_left : 0; *fail_cnt = tally.fail_cnt; return *left_time; } ukui-biometric-auth/polkit-agent/src/fullscreenbackground.h0000664000175000017500000001125715167732644023154 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef FULLSCREENMANAGER_H #define FULLSCREENMANAGER_H #include #include #include #include #include #include "usdblockshortcut.h" #include #include class MainWindow; class FullScreenBackground : public QWidget { Q_OBJECT public: explicit FullScreenBackground(QWidget *parent = nullptr); virtual ~FullScreenBackground(); /** * @brief getMainWindow 获取认证对话框 * @return 认证对话框指针 */ inline MainWindow *getMainWindow() { return m_wndMain; } /** * @brief initMainWindow 初始化认证对话框 * @param strIconName 认证图标名称 * @param strMsg 认证消息 * @param listUsers 认证用户列表 * @param subjectPid 项目进程号 * @param callerPid 调用者进程号 * @param actionDesc 动作描述 * @param isMavis 是否为mavis平台 * @param isSupportTableMode 是否支持平板模式 */ void initMainWindow( const QString &strIconName, const QString &strMsg, const QStringList &listUsers, const QString &subjectPid, const QString &callerPid, const PolkitQt1::ActionDescription &actionDesc, const bool &isMavis, const bool &isSupportTableMode); /** * @brief showDialog 显示认证对话框 */ void showDialog(); /** * @brief closeDialog 关闭认证对话框 */ void closeDialog(); protected: /** * @brief paintEvent 绘制事件处理 * @param event 事件指针 */ void paintEvent(QPaintEvent *event); /** * @brief closeEvent 窗口关闭事件处理 * @param event 事件指针 */ void closeEvent(QCloseEvent *event); /** * @brief resizeEvent 窗口大小改变事件处理 * @param event 事件指针 */ void resizeEvent(QResizeEvent *event); bool eventFilter(QObject *obj, QEvent *event); private Q_SLOTS: /** * @brief onScreenCountChanged 屏幕数变化处理 */ #if QT_VERSION_MAJOR == 6 void onScreenCountChanged(); #else void onScreenCountChanged(int); #endif /** * @brief onDesktopResized 桌面大小变化处理 */ void onDesktopResized(); /** * @brief onPrimaryScreenChanged 主屏变化处理 */ void onPrimaryScreenChanged(); /** * @brief onWorkAreaResized 工作区大小变化处理 */ void onWorkAreaResized(); void onCurrentScreenChanged(QScreen *screen); private: /** * @brief initUI 初始化UI */ void initUI(); /** * @brief initConnections 初始化信号槽连接 */ void initConnections(); /** * @brief isSupportCompositing 是否支持窗口复合 * @return true 支持,否则不支持 */ bool isSupportCompositing(); /** * @brief getBackground 获取背景 * @return 背景pixmap */ QPixmap getBackground(); /** * @brief getAccountBackground 获取账户背景 * @return 背景路径 */ QString getAccountBackground(); /** * @brief moveToScreen 移动认证弹窗到指定屏幕 * @param screen 屏幕信息指针 */ void moveToScreen(QScreen *screen); /** * @brief moveToCursorScreen 移动认证窗口到光标屏幕 */ void moveToCursorScreen(); /** * @brief blockSomeShortCut 禁启用快捷键 * @param isBlock 是否为禁用 */ void blockSomeShortCut(bool isBlock = false); private: MainWindow *m_wndMain = nullptr; // 认证对话框 QPixmap m_pixmapBackground; // 背景图 bool m_isFirstShow = true; // 第一次显示才主动移动对话框居中 USDBlockShortCut *m_usdBlockShortCut = nullptr; // usd禁启用快捷键实例 bool m_isWayland = false; UkuiWindowHelper *m_windowHelper = nullptr; QString m_curScreenName = ""; }; #endif // FULLSCREENMANAGER_H ukui-biometric-auth/polkit-agent/src/kalabel.cpp0000664000175000017500000000332115167732644020671 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "kalabel.h" KALabel::KALabel(QWidget *parent) : QLabel(parent) { m_strText = ""; } KALabel::KALabel(QString strText, QWidget *parent) : QLabel(strText, parent) { m_strText = strText; } void KALabel::setText(const QString &strText) { m_strText = strText; QLabel::setText(strText); } void KALabel::paintEvent(QPaintEvent *event) { QString strEText = getElidedText(font(), width(), m_strText); if (strEText != m_strText) { QLabel::setText(strEText); setToolTip(m_strText); } else { QLabel::setText(m_strText); setToolTip(""); } QLabel::paintEvent(event); } QString KALabel::getElidedText(QFont font, int width, QString strInfo) { QFontMetrics fontMetrics(font); //如果当前字体下,字符串长度大于指定宽度 #if QT_VERSION_MAJOR == 6 if (fontMetrics.horizontalAdvance(strInfo) > width) { #else if (fontMetrics.width(strInfo) > width) { #endif strInfo = QFontMetrics(font).elidedText(strInfo, Qt::ElideRight, width); } return strInfo; } ukui-biometric-auth/polkit-agent/src/usdblockshortcut.h0000664000175000017500000000301715167732630022342 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef USDBLOCKSHORTCUT_H #define USDBLOCKSHORTCUT_H #include #include #include #include class USDBlockShortCut : public QObject, public QDBusContext { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.settingsDaemon.shortcut") Q_PROPERTY(QStringList blockShortcuts READ blockShortcuts) public: USDBlockShortCut(QObject *parent = nullptr); virtual ~USDBlockShortCut(); public slots: /** * @brief blockShortcuts 禁用按键列表 * @return 禁用按键字符串列表 */ QStringList blockShortcuts(); private: bool m_isRegistService = false; /**是否已注册服务*/ bool m_isRegistObject = false; /**是否已注册对象*/ QString m_strDbusPath; /**dbus服务路径*/ }; #endif // USDBLOCKSHORTCUT_H ukui-biometric-auth/polkit-agent/src/usdblockshortcut.cpp0000664000175000017500000000445215167732644022706 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "usdblockshortcut.h" #include #include #include #include USDBlockShortCut::USDBlockShortCut(QObject *parent) : QObject(parent) { QString displayNum = QString(qgetenv("DISPLAY")).replace(":", "").replace(".", "_"); m_strDbusPath = QString("%1%2").arg(QString("org.ukui.settingsDaemon.shortcut.ukui-polkit")).arg(displayNum); m_isRegistService = QDBusConnection::sessionBus().registerService(m_strDbusPath); if (!m_isRegistService) { qInfo() << "registerService " << m_strDbusPath << " failed!!"; } else { m_isRegistObject = QDBusConnection::sessionBus().registerObject( "/org/ukui/settingsDaemon/shortcut", "org.ukui.settingsDaemon.shortcut", this, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllProperties); if (!m_isRegistObject) { qInfo() << "registerObject /org/ukui/settingsDaemon/shortcut failed!!"; } } } USDBlockShortCut::~USDBlockShortCut() { if (m_isRegistObject) { QDBusConnection::sessionBus().unregisterObject("/org/ukui/settingsDaemon/shortcut"); m_isRegistObject = false; } if (m_isRegistService) { QDBusConnection::sessionBus().unregisterService(m_strDbusPath); m_isRegistService = false; } } QStringList USDBlockShortCut::blockShortcuts() { QStringList listShortCut = { "WINDOWSWITCH_KEY", "WLCOM_SWITCH_WORKSPACE", "WLCOM_WINDOW_ACTION", "WLCOM_MAXIMIZED_VIEWS", "WLCOM_CTRL_VIEWS", "KDS_KEY" }; return listShortCut; } ukui-biometric-auth/polkit-agent/src/fullscreenbackground.cpp0000664000175000017500000005167215167732644023514 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "fullscreenbackground.h" #include "mainwindow.h" #include #include #include #include #include "../common/qt_desktop_compat.h" #include #include #include #include #if QT_VERSION_MAJOR == 6 #include #else #include #endif #include using namespace kdk; #define PERSONALSIE_SCHEMA "org.mate.background" #define PERSONALSIE_TRAN_KEY "picture-filename" #define USD_MEDIA_KEYS_SCHEMA "org.ukui.SettingsDaemon.plugins.media-keys" #define USD_MEDIA_KEYS_WINDOW_SWTICH_KEY "ukuiWindowSwitch" #define USD_MEDIA_KEYS_WINDOW_SWTICH2_KEY "ukuiWindowSwitch2" FullScreenBackground::FullScreenBackground(QWidget *parent) : QWidget(parent) { m_isWayland = QString(qgetenv("XDG_SESSION_TYPE")) == "wayland"; initUI(); initConnections(); } FullScreenBackground::~FullScreenBackground() { closeDialog(); } void FullScreenBackground::initMainWindow( const QString &strIconName, const QString &strMsg, const QStringList &listUsers, const QString &subjectPid, const QString &callerPid, const PolkitQt1::ActionDescription &actionDesc, const bool &isMavis, const bool &isSupportTableMode) { if (!m_wndMain) { if (m_isWayland) { m_wndMain = new MainWindow(); m_wndMain->setWindowFlags(windowFlags() | Qt::Tool | Qt::WindowStaysOnTopHint); #if QT_VERSION_MAJOR < 6 KWindowSystem::setState(m_wndMain->winId(), NET::State::KeepAbove | NET::State::SkipTaskbar); #endif } else { m_wndMain = new MainWindow(this); m_wndMain->setModal(true); } setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint & ~Qt::WindowMinimizeButtonHint); m_wndMain->setWindowTitle(tr("Authentication")); WindowManager::setSkipTaskBar(m_wndMain->windowHandle(), true); m_wndMain->setIcon(strIconName); m_wndMain->setCurProject(isMavis); m_wndMain->setHeader(strMsg); m_wndMain->setUsers(listUsers); m_wndMain->setEditInputMethod(isSupportTableMode); m_wndMain->setFixedSize(420, 337); /* * mainWindow->setDetails(subjectPid, callerPid, actionDesc.actionId(), actionDesc.description(), actionDesc.vendorName(), actionDesc.vendorUrl()); */ connect(m_wndMain, &MainWindow::finished, this, [=](int nResult) { qDebug() << "auth dialog finished:" << nResult; }); } m_windowHelper = new UkuiWindowHelper(m_wndMain); m_windowHelper->setWindowRole(UkuiWindowHelper::WindowRole::Authentication); if (m_isWayland) { hide(); connect(m_windowHelper, &UkuiWindowHelper::currentScreenChanged, this, &FullScreenBackground::onCurrentScreenChanged); QTimer::singleShot(0, this, [&, this]() { m_windowHelper->requestGetCurrentScreen();}); } else { show(); } } void FullScreenBackground::initUI() { setWindowTitle(tr("Authentication")); if (m_isWayland) { setAttribute(Qt::WA_TranslucentBackground); setGeometry(0, 0, 0, 0); } else { setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint); setWindowOpacity(0.25); #if QT_VERSION_MAJOR == 6 // Qt6/KF6中使用KX11Extras::setWindowState方法 KX11Extras::setState(winId(), NET::KeepAbove | NET::SkipTaskbar); #else KWindowSystem::setState(winId(), NET::State::KeepAbove | NET::State::SkipTaskbar); #endif WindowManager::setSkipTaskBar(this->windowHandle(), true); installEventFilter(this); if (!isSupportCompositing()) { m_pixmapBackground = getBackground(); } setGeometry(0, 0, 7680, 4320); } qDebug() << "Window geometry:" << geometry(); } void FullScreenBackground::initConnections() { // 使用兼容性函数连接屏幕变化信号 #if QT_VERSION_MAJOR == 6 connectScreenSignals(this, &FullScreenBackground::onScreenCountChanged); #else connectScreenSignals(this, SLOT(onScreenCountChanged())); #endif } #if QT_VERSION_MAJOR == 6 void FullScreenBackground::onScreenCountChanged() #else void FullScreenBackground::onScreenCountChanged(int) #endif { qDebug() << "onScreenCountChanged----"; if (m_isWayland) { m_windowHelper->requestGetCurrentScreen(); update(); QTimer::singleShot(100, this, [&, this]() { moveToCursorScreen();}); return; } // 使用兼容性函数获取桌面几何信息 QRect screenGeometry = getDesktopGeometry(); if ((screenGeometry.x() != 0 || screenGeometry.y() != 0) && this->geometry().contains(screenGeometry) && (getScreenCount() == 1)) { return; } if (screenGeometry.height() > height() || screenGeometry.width() > width()) { setGeometry( screenGeometry.x(), screenGeometry.y(), screenGeometry.width() + 1, screenGeometry.height() + 1); } update(); moveToCursorScreen(); qDebug() << screenGeometry; } void FullScreenBackground::onWorkAreaResized() { qDebug() << "onWorkAreaResized----"; update(); } void FullScreenBackground::onPrimaryScreenChanged() { qDebug() << "onPrimaryScreenChanged----"; if (m_isWayland) { m_windowHelper->requestGetCurrentScreen(); } update(); QTimer::singleShot(100, this, [&, this]() { moveToCursorScreen();}); } void FullScreenBackground::onDesktopResized() { qDebug() << "onDesktopResized----"; if (m_isWayland) { m_windowHelper->requestGetCurrentScreen(); update(); QTimer::singleShot(100, this, [&, this]() { moveToCursorScreen();}); return; } // 使用兼容性函数获取桌面几何信息 QRect screenGeometry = getDesktopGeometry(); if ((screenGeometry.x() != 0 || screenGeometry.y() != 0) && this->geometry().contains(screenGeometry) && (getScreenCount() == 1)) { return; } if (screenGeometry.height() > height() || screenGeometry.width() > width()) { setGeometry( screenGeometry.x(), screenGeometry.y(), screenGeometry.width() + 1, screenGeometry.height() + 1); } update(); moveToCursorScreen(); qDebug() << screenGeometry; } void FullScreenBackground::showDialog() { if (m_isFirstShow) { m_isFirstShow = false; blockSomeShortCut(true); if (!m_isWayland) { show(); } if (m_wndMain) { qDebug() << "DialogGeometry:" << m_wndMain->geometry(); m_wndMain->show(); m_wndMain->activateWindow(); // move auth dialog to cursor screen moveToCursorScreen(); } } } void FullScreenBackground::closeDialog() { blockSomeShortCut(false); if (m_wndMain) { m_wndMain->hide(); m_wndMain->stopDoubleAuth(); m_wndMain->close(); m_wndMain->deleteLater(); m_wndMain = nullptr; } } bool FullScreenBackground::isSupportCompositing() { if (QString(qgetenv("XDG_SESSION_TYPE")) == "wayland") { return true; } QDBusInterface kwinCompositor( "org.ukui.KWin", "/Compositor", "org.freedesktop.DBus.Properties", QDBusConnection::sessionBus()); QDBusReply sessionReply = kwinCompositor.call("Get", "org.kde.kwin.Compositing", "compositingType"); if (!sessionReply.isValid()) { qWarning() << sessionReply.error(); } else { QString strType = sessionReply.value().variant().toString(); if (strType.isEmpty() || strType == "none") return false; } return true; } QPixmap FullScreenBackground::getBackground() { QPixmap pixmapBackground; QString strPicName = ""; // 获取桌面壁纸路径 QGSettings *personalGSettings = nullptr; if (QGSettings::isSchemaInstalled(PERSONALSIE_SCHEMA)) { personalGSettings = new QGSettings(PERSONALSIE_SCHEMA, QByteArray(), this); QStringList keys = personalGSettings->keys(); if (keys.contains(PERSONALSIE_TRAN_KEY)) { strPicName = personalGSettings->get(PERSONALSIE_TRAN_KEY).toString(); } delete personalGSettings; personalGSettings = nullptr; } // 文件存在且可读则加载图片 QFileInfo fileInfo(strPicName); if (fileInfo.exists() && fileInfo.isReadable()) { // do nothing } else { strPicName = getAccountBackground(); } if (!strPicName.isEmpty()) { QImageReader reader; reader.setFileName(strPicName); reader.setAutoTransform(true); reader.setDecideFormatFromContent(true); pixmapBackground = QPixmap::fromImageReader(&reader); } return pixmapBackground; } QString FullScreenBackground::getAccountBackground() { QString strTmpPicName = "/usr/share/backgrounds/ubuntukylin-default-settings.jpg"; uid_t uid = getuid(); QDBusInterface iface( "org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", QDBusConnection::systemBus()); QDBusReply userPath = iface.call("FindUserById", (qint64)uid); if (!userPath.isValid()) { return strTmpPicName; } else { QDBusInterface userIface( "org.freedesktop.Accounts", userPath.value().path(), "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusReply backgroundReply = userIface.call("Get", "org.freedesktop.Accounts.User", "BackgroundFile"); if (backgroundReply.isValid()) { QString strPicName = backgroundReply.value().variant().toString(); if (!strPicName.isEmpty()) { QFileInfo fileInfo(strPicName); if (fileInfo.exists() && fileInfo.isReadable()) { return strPicName; } } } } return strTmpPicName; } void FullScreenBackground::moveToScreen(QScreen *screen) { // 将主全屏更新到新屏幕上,并重新将对话框居中 if (!screen) { return; } if (m_wndMain) { QRect rectParent = screen->geometry(); QRect rectDes = QRect( rectParent.x() + (rectParent.width() - m_wndMain->width()) / 2, rectParent.y() + (rectParent.height() - m_wndMain->height()) / 2, m_wndMain->width(), m_wndMain->height()); m_wndMain->setGeometry(rectDes); qDebug() << "new rect:" << rectParent << "," << rectDes << "," << m_wndMain->geometry(); } } void FullScreenBackground::moveToCursorScreen() { bool isFoundScreen = false; if (m_isWayland) { QString strCurScreen = WindowManager::currentOutputName(); if(!m_curScreenName.isEmpty()){ strCurScreen = m_curScreenName; } for (auto screen : QApplication::screens()) { qDebug() << "Screen:" << screen->name() << "," << screen->geometry(); if (screen && screen->name() == strCurScreen) { isFoundScreen = true; moveToScreen(screen); break; } } } else { QPoint cursor = QCursor::pos(); for (auto screen : QApplication::screens()) { qDebug() << "Screen:" << screen->name() << "," << screen->geometry(); if (screen && screen->geometry().contains(cursor)) { isFoundScreen = true; moveToScreen(screen); break; } } } if (!isFoundScreen) { if (QApplication::primaryScreen()) { moveToScreen(QApplication::primaryScreen()); } isFoundScreen = true; } } void FullScreenBackground::paintEvent(QPaintEvent *event) { if (!m_isWayland) { for (auto screen : QApplication::screens()) { QPainter painter(this); if (!m_pixmapBackground.isNull()) { painter.drawPixmap(screen->geometry(), m_pixmapBackground); } } } return QWidget::paintEvent(event); } void FullScreenBackground::closeEvent(QCloseEvent *event) { qDebug() << "FullScreenBackground::closeEvent"; if (!m_isWayland) { // 使用兼容性函数断开屏幕变化信号 #if QT_VERSION_MAJOR == 6 disconnectScreenSignals(this, &FullScreenBackground::onScreenCountChanged); #else disconnectScreenSignals(this, SLOT(onScreenCountChanged())); #endif } return QWidget::closeEvent(event); } void FullScreenBackground::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); qDebug() << "WndSize:" << this->size(); } void FullScreenBackground::blockSomeShortCut(bool isBlock /* = false*/) { static bool sIsBlocked = false; if (sIsBlocked == isBlock) { return; } QStringList listBlockShortCut = { "Minimize All Window", // 最小化所有窗口 "Minimize Or Unminimize All Window Besides Active Window", // 最小化或还原非焦点窗口 "Multitask View show", // 显示工作区 "Show/Hide Desktop", // 显示/隐藏桌面 "ShowDesktopGrid", // Show Desktop Grid "ShowMultitaskView", // Show Multitask View "Switch One Desktop Down", // 切换到下面的桌面 "Switch One Desktop Up", // 切换到上面的桌面 "Switch One Desktop to the Left", // 切换到左边的工作区 "Switch One Desktop to the Right", // 切换到右边的工作区 "Switch to Desktop 1", // 切换到桌面 1 "Switch to Desktop 2", // 切换到桌面 2 "Switch to Desktop 3", // 切换到桌面 3 "Switch to Desktop 4", // 切换到桌面 4 "Switch to Next Screen", // 切换到下一屏幕 "Switch to Previous Screen", // 切换到上一个屏幕 "Toggle Window Raise/Lower", // 窗口置前或置后 "Unminimize All Window", // 还原所有最小化窗口 "Walk Through Desktop List", // 遍历桌面列表 "Walk Through Desktop List (Reverse)", // 遍历桌面列表(反向) "Walk Through Desktops", // 遍历桌面 "Walk Through Desktops (Reverse)", // 遍历桌面(反向) "Walk Through Windows", // 遍历窗口 "Walk Through Windows (Reverse)", // 遍历窗口(反向) "Walk Through Windows Alternative", // 遍历窗口候选 "Walk Through Windows Alternative (Reverse)", // 遍历窗口候选(反向) "Walk Through Windows of Current Application", // 遍历当前应用程序窗口 "Walk Through Windows of Current Application (Reverse)", // 遍历当前应用程序窗口(反向) "Walk Through Windows of Current Application Alternative", // 遍历当前应用程序窗口候选 "Walk Through Windows of Current Application Alternative (Reverse)", // 遍历当前应用程序窗口候选(反向) "Walk Through fullscreenWindows", // 遍历所有最大化或全屏窗口 "Window Lower", // 降低窗口 "Window Maximize", // 最大化窗口 "Window Maximize Horizontal", // 水平最大化窗口 "Window Maximize Vertical", // 垂直最大化窗口 "Window Minimize", // 最小化窗口 "Window On All Desktops", // 将窗口放到全部桌面 "Window One Desktop Down", // 窗口下移一个桌面 "Window One Desktop Up", // 窗口上移一个桌面 "Window One Desktop to the Left", // 窗口左移一个桌面 "Window One Desktop to the Right", // 窗口右移一个桌面 "Window Operations Menu", // 窗口操作菜单 "Window Quick Move And Maximize Left Screen", // 窗口快速移动并最大化到下一个屏幕 "Window Quick Move And Maximize Right Screen", // 窗口快速移动并最大化到上一个屏幕 "Window Quick Move Left Screen", // 窗口快速移动到下一个屏幕 "Window Quick Move Right Screen", // 窗口快速移动到上一个屏幕 "Window to Desktop 1", // 窗口到桌面 1 "Window to Desktop 2", // 窗口到桌面 2 "Window to Desktop 3", // 窗口到桌面 3 "Window to Desktop 4", // 窗口到桌面 4 "Window to Next Desktop", // 窗口到下一桌面 "Window to Next Screen", // 窗口到下一屏幕 "Window to Previous Desktop", // 窗口到前一桌面 "Window to Previous Screen", // 窗口到前一屏幕 "Window to Screen 0", // 窗口到屏幕 0 "Window to Screen 1", // 窗口到屏幕 1 "Window to Screen 2", // 窗口到屏幕 2 "Window to Screen 3", // 窗口到屏幕 3 "Window to Screen 4", // 窗口到屏幕 4 }; sIsBlocked = isBlock; if (sIsBlocked) { if (!m_isWayland) { // kwin shortcut QDBusInterface kwinInterface("org.ukui.KWin", "/KWin", "org.kde.KWin", QDBusConnection::sessionBus()); for (QString strShortCut : listBlockShortCut) { QDBusMessage blockMessage = kwinInterface.call("blockShortcut", strShortCut, true); if (blockMessage.type() == QDBusMessage::ErrorMessage) { qWarning() << "Kwin dbus error:" << blockMessage.errorMessage(); break; } } } // usd shortcut if (!m_usdBlockShortCut) { m_usdBlockShortCut = new USDBlockShortCut(this); } } else { if (!m_isWayland) { // kwin shortcut QDBusInterface kwinInterface("org.ukui.KWin", "/KWin", "org.kde.KWin", QDBusConnection::sessionBus()); for (QString strShortCut : listBlockShortCut) { QDBusMessage blockMessage = kwinInterface.call("blockShortcut", strShortCut, false); if (blockMessage.type() == QDBusMessage::ErrorMessage) { qWarning() << "Kwin dbus error1:" << blockMessage.errorMessage(); break; } } } // usd shortcut if (m_usdBlockShortCut) { delete m_usdBlockShortCut; m_usdBlockShortCut = nullptr; } } } bool FullScreenBackground::eventFilter(QObject *obj, QEvent *event) { return QWidget::eventFilter(obj, event); } void FullScreenBackground::onCurrentScreenChanged(QScreen *screen) { if(screen){ qDebug()<<"onCurrentScreenChanged "<geometry(); m_curScreenName = screen->name(); } } ukui-biometric-auth/polkit-agent/src/mainwindow.h0000664000175000017500000001426015167732644021123 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include "biometric.h" #include "users.h" #include "pam-tally.h" #include #include #include #include "bioauthwidget.h" #include "loginoptionswidget.h" #include "modeButton.h" #include "kalabel.h" #include #include using namespace kdk; namespace Ui { class MainWindow; } class MainWindow : public kdk::KDialog { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); void closeEvent(QCloseEvent *event); bool eventFilter(QObject *obj, QEvent *event); void paintEvent(QPaintEvent *event); void keyPressEvent(QKeyEvent *event); //屏蔽esc按钮 enum Mode { UNDEFINED, PASSWORD, BIOMETRIC, DEVICES }; enum situation { TRUE, ERROR }; void setIcon(const QString &iconName); void setHeader(const QString &text); void setUsers(const QStringList &usersList); void setDetails( const QString &subPid, const QString &callerPid, const QString &actionId, const QString &actionDesc, const QString vendorName, const QString vendorUrl); void setPrompt(const QString &text, bool echo); void setMessage(const QString &text, situation situat = ERROR); void setAuthResult(bool result, const QString &text = ""); void clearEdit(); void switchAuthMode(Mode mode); void setDoubleAuth(bool val); void stopDoubleAuth(); QString check_is_pam_message(QString text); void switchLoginOptType(unsigned uLoginOptType); void setEditInputMethod(bool bEnable); void setCurProject(bool isMavis); void setUkeyTypeTip(QString text); void startLoadingUkey(); void stopLoadingUkey(); void updateLoadingPixmap(); void updateAuthMethod(); void resetSendPassword(); bool checkIsAdmin(QString userName); private: uid_t getUid(const QString &userName); void setMovie(); void setPixmap(); void startBioAuth(unsigned uTimeout = 200); void switchWidget(Mode mode); int enable_biometric_authentication(); void root_unlock_countdown(); void unlock_countdown(); void editIcon(); void setLoginTypeTip(QString strLoginTypeTip); void setMavisSheel(); void updatePixmap(); void setBiometricAuthDisabledStatus(bool locked); QString getAuthMethod(); public slots: void onUpdateBioAuthMsg(QString strMsg); void onUpdateWndSize(unsigned uLoginOptType, unsigned uLoginOptSize); void onShowYesPrompt(); private slots: /** * @brief onOptionSelected * @param uCurLoginOptType * @param deviceInfo */ void onOptionSelected(unsigned uCurLoginOptType, const DeviceInfoPtr &deviceInfo); /** * @brief onNotifyOptionsChanged * @param uOptionsCount */ void onNotifyOptionsChanged(unsigned uOptionsCount); /** * @brief onLoginOptionsAuthCompleted * @param uid * @param ret * @param nStatus */ void onLoginOptionsAuthCompleted(uid_t uid, bool ret, int nStatus); void on_btnDetails_clicked(); void on_lePassword_returnPressed(); void on_ukeyPassword_returnPressed(); void on_btnBioAuth_clicked(); void on_returnButton_clicked(); void on_cmbUsers_currentTextChanged(const QString &userName); void on_btnCancel_clicked(); void on_btnAuth_clicked(); void restart_bio_identify(); void startBioAuthDelay(); void onConfigurationChanged(QString key); void onLockStatus(); void onUnlockStatus(); void onRespondUkey(const QString &text); signals: void accept(const QString &text); void canceled(); void switchToPassword(); void switchToBiometric(); void userChanged(const QString &userName); void restartAuth(); void yesPrompted(); private: Ui::MainWindow *ui; Users *users; QString userName; bool enableBioAuth; bool receiveBioPAM; BioDevices bioDevices; Mode authMode; bool isFirst; bool useDoubleAuth; bool isbioSuccess; QMap> m_failMap; int maxFailedTimes; bool isHiddenSwitchButton; ModeButton *m_modeButton; QIcon modeIcon; bool pwdShow = false; bool isHover = false; // ukey优先级比密码低,该变量用于判断是否第一次认证,并选中密码 bool isFirstAuth = true; QTimer *m_timer; // const DeviceInfo *device = NULL; bool isLockingFlg; //判断当前是否正在锁定倒计时 int m_nCurLockMin; //当前锁定的分钟数 // 登录选项 KALabel *m_labelTip = nullptr; LoginOptionsWidget *m_loginOptsWidget = nullptr; unsigned m_uCurLoginOptType = LOGINOPT_TYPE_PASSWORD; // 当前登录验证方式 QString m_strLoginTypeTip = ""; QTimer *m_bioTimer = nullptr; DeviceInfoPtr m_deviceInfo = nullptr; bool m_isNetworkErr = false; //标题栏 QHBoxLayout *headerLayout; QLabel *logoLabel; QLabel *titleLabel; QPushButton *closeBtn; QGSettings *settings; int fontSize; QString app_IconName; int m_nLastDeviceId = -1; bool no_changes = false; bool is_Mavis = false; QTimer *w_timer; QPixmap m_waitingPixmap; QTimer *m_loadingTimer = nullptr; QPixmap m_loadingPixmap; bool isLoadingUkey = false; bool doNotNeedAuth = false; bool hasSendPassword = false; QString authMethod = ""; UkuiWindowHelper *m_windowHelper = nullptr; }; #endif // MAINWINDOW_H ukui-biometric-auth/polkit-agent/src/users.cpp0000664000175000017500000001125415167732630020436 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "users.h" #include #include #include #include #include #include "types.h" #include #include QDebug operator<<(QDebug stream, const UserItem &user) { stream << user.name << user.realName << user.uid << user.icon << user.path; return stream; } Users::Users(QObject *parent) : QObject(parent) { defaultIcon = ":/image/assets/iconFace.png"; loadUsers(); } QList Users::getUsers() { return users; } UserItem Users::getUserByName(const QString &name) { for (int i = 0; i < users.size(); i++) { if (users.at(i).name == name) { return users.at(i); } } UserItem user; if (name == "root") { user.icon = "/root/.face"; if (!QFile(user.icon).exists()) { user.icon = defaultIcon; } } else { user.icon = qgetenv("HOME") + "/.face"; if (!QFile(user.icon).exists()) { user.icon = defaultIcon; } } user.name = name; user.path = ""; user.uid = getuid(); return user; } QString Users::getDefaultIcon() { return defaultIcon; } // https://stackoverflow.com/questions/20206376/ // how-do-i-extract-the-returned-data-from-qdbusmessage-in-a-qt-dbus-call void Users::loadUsers() { qDebug() << "loadUsers"; actService = new QDBusInterface(ACT_DBUS_SERVICE, ACT_DBUS_PATH, ACT_DBUS_INTERFACE, QDBusConnection::systemBus()); connect(actService, SIGNAL(UserAdded(const QDBusObjectPath &)), this, SLOT(onUserAdded(const QDBusObjectPath &))); connect( actService, SIGNAL(UserDeleted(const QDBusObjectPath &)), this, SLOT(onUserDeleted(const QDBusObjectPath &))); QDBusMessage ret = actService->call("ListCachedUsers"); QList outArgs = ret.arguments(); //(QVariant(QDBusArgument,)) QVariant first = outArgs.at(0); // QVariant(QDBusArgument,) const QDBusArgument &dbusArgs = first.value(); QDBusObjectPath path; dbusArgs.beginArray(); while (!dbusArgs.atEnd()) { dbusArgs >> path; getUser(path.path()); } dbusArgs.endArray(); } UserItem Users::getUser(const QString &path) { QDBusInterface iface(ACT_DBUS_SERVICE, path, DBUS_PROP_INTERFACE, QDBusConnection::systemBus()); QDBusMessage ret = iface.call("GetAll", ACT_USER_INTERFACE); QList outArgs = ret.arguments(); QVariant first = outArgs.at(0); const QDBusArgument &dbusArgs = first.value(); UserItem user; user.path = path; dbusArgs.beginMap(); while (!dbusArgs.atEnd()) { QString key; QVariant value; dbusArgs.beginMapEntry(); dbusArgs >> key >> value; if (key == "UserName") { user.name = value.toString(); } else if (key == "RealName") { user.realName = value.toString(); } else if (key == "IconFile") { user.icon = value.toString(); if (!QFile(user.icon).exists()) { user.icon = defaultIcon; } } else if (key == "Uid") { user.uid = value.toUInt(); } dbusArgs.endMapEntry(); } dbusArgs.endMap(); if (user.realName.isEmpty()) { user.realName = user.name; } users.push_back(user); return user; } void Users::onUserAdded(const QDBusObjectPath &path) { int index = findUserByPath(path.path()); if (index >= 0 && index < users.count()) { UserItem user = getUser(path.path()); Q_EMIT userAdded(user); } } void Users::onUserDeleted(const QDBusObjectPath &path) { int index = findUserByPath(path.path()); if (index >= 0 && index < users.count()) { UserItem user = users.at(index); users.removeAt(index); Q_EMIT userDeleted(user); } } int Users::findUserByPath(const QString &path) { auto iter = std::find_if(users.begin(), users.end(), [&](const UserItem &user) { return user.path == path; }); int index = iter - users.begin(); return index; } ukui-biometric-auth/polkit-agent/src/main.qss0000664000175000017500000000000015167732630020230 0ustar fengfengukui-biometric-auth/polkit-agent/src/mainwindow.ui0000664000175000017500000003266315167732644021320 0ustar fengfeng MainWindow 0 0 459 716 0 0 430 0 Form 8 QLayout::SetDefaultConstraint 0 8 0 24 8 24 0 24 0 382 0 382 16777215 75 true true true 0 0 0 0 116 8 0 0 0 0 true true 0 116 0 0 0 9 8 0 0 0 Qt::AlignCenter Qt::NoContextMenu 0 25 Qt::LeftToRight Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true 0 80 0 0 0 8 0 Qt::NoContextMenu 0 25 Qt::LeftToRight Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true 0 24 0 24 0 Qt::Vertical 20 40 16 24 0 24 0 36 ArrowCursor Biometric Qt::Horizontal 10 36 0 0 0 36 ArrowCursor Cancel 0 0 0 36 ArrowCursor Authenticate 0 36 true 0 36 use password KALabel QLabel
./src/kalabel.h
ukui-biometric-auth/polkit-agent/src/pam-tally.h0000664000175000017500000000350515167732630020642 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef PAM_TALLY_H #define PAM_TALLY_H #include #ifdef __cplusplus extern "C" { #endif #define SHM_TALLY "/shm_tally" struct _pam_tally { int deny; //失败次数上限 int unlock_time; //普通用户失败次数达到上限后,多少秒之后才能解锁 int root_unlock_time; // root用户失败次数达到上限后,多少秒之后才能解锁 int failed; //当前失败的次数 time_t lock_start_time; //失败次数达到上限后,开始计时 }; typedef struct _pam_tally pam_tally; int pam_tally_init(); int pam_tally_add_failed(); int pam_tally_clear_failed(); int pam_tally_falure_is_out(); int pam_tally_deny(); int pam_tally_failed_count(); int pam_tally_unlock_time(); int pam_tally_is_enbled(); int pam_tally_is_canUnlock(); int pam_tally_unlock_time_left(int uid, int *fail_cnt, int *left_time, int *deny, int *fail_time, int *unlock_time); int pam_tally_root_unlock_time_left(int *fail_cnt, int *left_time, int *deny, int *fail_time, int *unlock_time1); #ifdef __cplusplus } #endif #endif // PAM_TALLY_H ukui-biometric-auth/polkit-agent/src/sessionmanager.cpp0000664000175000017500000000547415167732630022322 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "sessionmanager.h" #include #include #include #include #define SM_DBUS_SERVICE "org.gnome.SessionManager" #define SM_DBUS_PATH "/org/gnome/SessionManager" #define SM_DBUS_INTERFACE "org.gnome.SessionManager" #define SM_DBUS_CLIENT_INTERFACE "org.gnome.SessionManager.ClientPrivate" SessionManager::SessionManager(QObject *parent) : QObject(parent) { smInterface = new QDBusInterface(SM_DBUS_SERVICE, SM_DBUS_PATH, SM_DBUS_INTERFACE, QDBusConnection::sessionBus()); QString appId("polkit-ukui-authentication-agent-1.desktop"); QString clientStartupId(qgetenv("DESKTOP_AUTOSTART_ID")); QDBusReply reply = smInterface->call("RegisterClient", appId, clientStartupId); if (!reply.isValid()) { qWarning() << "Register Client to gnome session failed"; } clientId = reply.value().path(); qDebug() << "Register Client to gnome session: " << reply.value().path(); clientInterface = new QDBusInterface(SM_DBUS_SERVICE, clientId, SM_DBUS_CLIENT_INTERFACE, QDBusConnection::sessionBus()); qDebug() << clientInterface->isValid(); QDBusConnection conn = clientInterface->connection(); conn.connect(SM_DBUS_SERVICE, clientId, SM_DBUS_CLIENT_INTERFACE, "Stop", this, SLOT(onStop())); conn.connect( SM_DBUS_SERVICE, clientId, SM_DBUS_CLIENT_INTERFACE, "EndSession", this, SLOT(onEndSession(unsigned int))); conn.connect(SM_DBUS_SERVICE, clientId, SM_DBUS_CLIENT_INTERFACE, "QueryEndSession", this, SLOT(onQueryEndSession(unsigned int))); } void SessionManager::onStop() { QApplication::quit(); } void SessionManager::onEndSession(unsigned int flag) { endSessionResponse(); } void SessionManager::onQueryEndSession(unsigned int flag) { endSessionResponse(); QApplication::quit(); } void SessionManager::endSessionResponse() { QDBusMessage msg = clientInterface->call("EndSessionResponse", true, ""); if (msg.type() == QDBusMessage::ErrorMessage) qDebug() << "Failed to call EndSessionResponse " << msg.errorMessage(); } ukui-biometric-auth/polkit-agent/src/modeButton.h0000664000175000017500000000274415167732630021066 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef MODEBUTTON_H #define MODEBUTTON_H #include #include #include #include #include class ModeButton : public QPushButton { Q_OBJECT public: explicit ModeButton(QWidget *parent = nullptr); ModeButton(QString strIcon, QWidget *parent = nullptr); virtual ~ModeButton(); QPixmap drawSymbolicColoredPixmap(QPixmap &source, QString cgColor); void initUI(); void setModeIcon(); bool isShowPwd(); protected: bool eventFilter(QObject *obj, QEvent *event) override; //事件过滤 private: void initStyleTheme(); private: QString m_strIcon; QString m_strText; QGSettings *m_styleSettings = nullptr; QString m_strThemeName = ""; bool pwdShow = false; bool m_isHover = false; }; #endif // MODEBUTTON_H ukui-biometric-auth/polkit-agent/src/users.h0000664000175000017500000000316715167732630020107 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef USERS_H #define USERS_H #include struct UserItem { QString name; QString realName; QString icon; quint64 uid; QString path; // accounts service path friend QDebug operator<<(QDebug stream, const UserItem &user); }; class QDBusInterface; class QDBusObjectPath; class Users : public QObject { Q_OBJECT public: explicit Users(QObject *parent = nullptr); QList getUsers(); UserItem getUserByName(const QString &name); QString getDefaultIcon(); private: void loadUsers(); UserItem getUser(const QString &path); int findUserByPath(const QString &path); private Q_SLOTS: void onUserAdded(const QDBusObjectPath &path); void onUserDeleted(const QDBusObjectPath &path); Q_SIGNALS: void userAdded(const UserItem &user); void userDeleted(const UserItem &user); private: QDBusInterface *actService; QList users; QString defaultIcon; }; #endif // USERS_H ukui-biometric-auth/polkit-agent/src/PolkitListener.h0000664000175000017500000000473215167732644021722 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef POLKITLISTENER_H #define POLKITLISTENER_H #include #include "mainwindow.h" #include "fullscreenbackground.h" #include #include #include #include #include #include #include using namespace PolkitQt1::Agent; class PolkitListener : public Listener { Q_OBJECT public: PolkitListener(QObject *parent = 0); virtual ~PolkitListener(); private: bool isSupportTableMode(); bool isMavis(); public slots: void initiateAuthentication( const QString &actionId, const QString &message, const QString &iconName, const PolkitQt1::Details &details, const QString &cookie, const PolkitQt1::Identity::List &identities, PolkitQt1::Agent::AsyncResult *result); bool initiateAuthenticationFinish(); void cancelAuthentication(); void finishObtainPrivilege(); private: bool gainedAuthorization = false; bool wasCancelled = false; bool wasSwitchToBiometric = false; bool inProgress; int numTries; QString implicitActiveStr; QPointer session; PolkitQt1::Identity::List identities; PolkitQt1::Identity currentIdentity; PolkitQt1::Agent::AsyncResult *result; QString cookie; FullScreenBackground *m_managerFullScreen; bool unacknowledged_messages = false; bool m_isSupportTableMode = false; bool m_isMavis = false; private slots: void startAuthentication(); void onShowPrompt(const QString &prompt, bool echo); void onShowError(const QString &text); void onShowInfo(const QString &text); void onResponse(const QString &text); void onAuthCompleted(bool); }; #endif /* POLKITLISTENER_H */ ukui-biometric-auth/polkit-agent/src/sessionmanager.h0000664000175000017500000000225615167732630021762 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef SESSIONMANAGER_H #define SESSIONMANAGER_H #include #include class SessionManager : public QObject { Q_OBJECT public: explicit SessionManager(QObject *parent = nullptr); signals: private slots: void onStop(); void onEndSession(unsigned int flag); void onQueryEndSession(unsigned int flag); void endSessionResponse(); private: QDBusInterface *smInterface; QDBusInterface *clientInterface; QString clientId; }; #endif // SESSIONMANAGER_H ukui-biometric-auth/polkit-agent/src/PolkitListener.cpp0000664000175000017500000003266615167732644022264 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include #include #include "PolkitListener.h" #include "mainwindow.h" #include "generic.h" #include PolkitListener::PolkitListener(QObject *parent) : Listener(parent), inProgress(false), currentIdentity(0), m_managerFullScreen(nullptr) { m_isSupportTableMode = isSupportTableMode(); m_isMavis = isMavis(); qDebug() << "isSupportTableMode:" << m_isSupportTableMode; } PolkitListener::~PolkitListener() {} bool PolkitListener::isMavis() { char *prjName = kdk_system_get_projectName(); if (prjName) { QString strFeature = QString(prjName); free(prjName); if (!strFeature.isEmpty()) { if(strFeature == "V10SP1-edu"){ m_isSupportTableMode = true; return true; } } } return false; } bool PolkitListener::isSupportTableMode() { unsigned int nFeature = kdk_system_get_productFeatures(); if (nFeature&0x02) { // 支持平板模式 return true; } return false; } /* initiateAuthentication message from polkit */ void PolkitListener::initiateAuthentication( const QString &actionId, const QString &message, const QString &iconName, const PolkitQt1::Details &details, const QString &cookie, const PolkitQt1::Identity::List &identities, PolkitQt1::Agent::AsyncResult *result) { if (inProgress) { result->setError(tr("Another client is already authenticating, please try again later.")); result->setCompleted(); qDebug() << "Another client is already authenticating, please try again later."; return; } QStringList usersList; QString subjectPid, callerPid; PolkitQt1::ActionDescription actionDesc; QString username = getenv("USER"); for(auto identity : identities){ if(identity.toString().remove("unix-user:") == username) usersList.prepend(identity.toString().remove("unix-user:")); else usersList.append(identity.toString().remove("unix-user:")); } subjectPid = details.lookup("polkit.subject-pid"); callerPid = details.lookup("polkit.caller-pid"); implicitActiveStr = details.lookup("implicit_authorization"); /* find action description for actionId */ foreach (const PolkitQt1::ActionDescription &desc, PolkitQt1::Authority::instance()->enumerateActionsSync()) { if (actionId == desc.actionId()) { actionDesc = desc; qDebug() << "Action description has been found"; break; } } qDebug() << "Initiating authentication"; qDebug() << "icon name: " << iconName; qDebug() << "identities: " << usersList; qDebug() << "message: " << message; qDebug() << "action id: " << actionId; qDebug() << "polkit.subject-pid" << subjectPid; qDebug() << "polkit.caller-pid" << callerPid; qDebug() << "action: " << actionDesc.description(); qDebug() << "Vendor:" << actionDesc.vendorName() << actionDesc.vendorUrl(); this->inProgress = true; this->identities = identities; this->cookie = cookie; this->result = result; session.clear(); if (identities.length() == 1) { this->currentIdentity = identities[0]; } else { currentIdentity = identities[0]; } /* Create the polkit window */ m_managerFullScreen = new FullScreenBackground(); m_managerFullScreen->initMainWindow( iconName, message, usersList, subjectPid, callerPid, actionDesc, m_isMavis, m_isSupportTableMode); if (m_managerFullScreen && m_managerFullScreen->getMainWindow()) { connect(m_managerFullScreen->getMainWindow(), &MainWindow::accept, this, &PolkitListener::onResponse); connect(m_managerFullScreen->getMainWindow(), &MainWindow::canceled, this, [&] { if (inProgress && !gainedAuthorization) { wasCancelled = true; unacknowledged_messages = false; if (!session.isNull()) { session.data()->cancel(); } finishObtainPrivilege(); } }); connect(m_managerFullScreen->getMainWindow(), &MainWindow::switchToBiometric, this, [&] { wasSwitchToBiometric = true; startAuthentication(); }); connect(m_managerFullScreen->getMainWindow(), &MainWindow::yesPrompted, this, [=] { result->setCompleted(); this->gainedAuthorization = true; finishObtainPrivilege(); }); connect(m_managerFullScreen->getMainWindow(), &MainWindow::restartAuth, this, [&] { startAuthentication(); }); connect(m_managerFullScreen->getMainWindow(), &MainWindow::userChanged, this, [&](const QString &userName) { for (int i = 0; i < this->identities.size(); i++) { auto identity = this->identities.at(i); if (identity.toString().remove("unix-user:") == userName) { this->currentIdentity = this->identities.at(i); numTries = 0; startAuthentication(); break; } } }); numTries = 0; wasCancelled = false; wasSwitchToBiometric = false; if (implicitActiveStr == "yes_prompt") { m_managerFullScreen->getMainWindow()->onShowYesPrompt(); m_managerFullScreen->getMainWindow()->setFixedSize(m_managerFullScreen->getMainWindow()->width(), 200); m_managerFullScreen->getMainWindow()->show(); m_managerFullScreen->getMainWindow()->activateWindow(); return; } m_managerFullScreen->getMainWindow()->userChanged(usersList.at(0)); } } static int get_pam_tally(int *deny, int *unlock_time) { char buf[128]; FILE *auth_file = NULL; if ((auth_file = fopen("/etc/pam.d/common-auth", "r")) == NULL) return -1; while (fgets(buf, sizeof(buf), auth_file)) { if (strnlen(buf,1024) == 0 || buf[0] == '#') continue; if (!strstr(buf, "deny")) continue; char *ptr = strtok(buf, " \t"); while (ptr) { if (strncmp(ptr, "deny=", 5) == 0) { sscanf(ptr, "deny=%d", deny); // gs_debug("-------------------- deny=%d", *deny); } if (strncmp(ptr, "unlock_time=", 12) == 0) { sscanf(ptr, "unlock_time=%d", unlock_time); // gs_debug("-------------------- unlock_time=%d", *unlock_time); } ptr = strtok(NULL, " \t"); } fclose(auth_file); auth_file = NULL; return 1; } fclose(auth_file); auth_file = NULL; return 0; } void PolkitListener::finishObtainPrivilege() { /* Number of tries increase only when some user is selected */ if (currentIdentity.isValid()) { numTries++; } qDebug().noquote() << QString("Finishing obtaining " "privileges (G:%1, C:%2, D:%3).") .arg(gainedAuthorization) .arg(wasCancelled) .arg(m_managerFullScreen && m_managerFullScreen->getMainWindow()); if (!gainedAuthorization && !wasCancelled && (m_managerFullScreen && m_managerFullScreen->getMainWindow())) { int deny = 0, unlock_time = 0; m_managerFullScreen->getMainWindow()->stopDoubleAuth(); if (!get_pam_tally(&deny, &unlock_time) || (deny == 0 && unlock_time == 0)) { // if(!wasSwitchToBiometric){ if (!unacknowledged_messages) m_managerFullScreen->getMainWindow()->setAuthResult( gainedAuthorization, tr("Authentication failure, please try again.")); //} startAuthentication(); return; } else { if (!unacknowledged_messages) { m_managerFullScreen->getMainWindow()->setAuthResult(gainedAuthorization, tr("Password input error!")); } startAuthentication(); return; } startAuthentication(); return; } if (m_managerFullScreen) { m_managerFullScreen->closeDialog(); m_managerFullScreen->deleteLater(); m_managerFullScreen = nullptr; } if ((implicitActiveStr == "yes_prompt") && wasCancelled) { result->setError("polkit-ukui-authentication-agent-1 cancel"); } if (!session.isNull()) { session.data()->result()->setCompleted(); session.data()->deleteLater(); session.clear(); } else { result->setCompleted(); } this->inProgress = false; implicitActiveStr = ""; qDebug() << "Finish obtain authorization:" << gainedAuthorization; gainedAuthorization = false; } void establishToBioPAM() { FILE *file; const char *data = "polkit-ukui-authentication-agent-1"; if ((file = fopen(BIO_COM_FILE, "w")) == NULL) { qWarning() << "open communication file failed: " << strerror(errno); return; } if (fputs(data, file) == EOF) { qWarning() << "write to communication file error: " << strerror(errno); } fclose(file); } void PolkitListener::startAuthentication() { qDebug() << "start authenticate user " << currentIdentity.toString(); unacknowledged_messages = false; if (!session.isNull()) { session.data()->deleteLater(); } /* We will create a new session only when some user is selected */ if (currentIdentity.isValid()) { establishToBioPAM(); session = new Session(currentIdentity, cookie, result); connect(session.data(), SIGNAL(request(QString, bool)), this, SLOT(onShowPrompt(QString, bool))); connect(session.data(), SIGNAL(completed(bool)), this, SLOT(onAuthCompleted(bool))); connect(session.data(), SIGNAL(showError(QString)), this, SLOT(onShowError(QString))); connect(session.data(), SIGNAL(showInfo(QString)), this, SLOT(onShowError(QString))); session.data()->initiate(); } if (m_managerFullScreen && m_managerFullScreen->getMainWindow()) { m_managerFullScreen->getMainWindow()->clearEdit(); m_managerFullScreen->getMainWindow()->updateAuthMethod(); m_managerFullScreen->getMainWindow()->resetSendPassword(); } } void PolkitListener::onShowPrompt(const QString &prompt, bool echo) { qDebug() << "Prompt: " << prompt << "echo: " << echo; if (!m_managerFullScreen || !m_managerFullScreen->getMainWindow()) { return; } if (prompt == BIOMETRIC_PAM || prompt == BIOMETRIC_PAM_QRCODE) { m_managerFullScreen->getMainWindow()->setDoubleAuth(false); m_managerFullScreen->getMainWindow()->switchAuthMode(MainWindow::BIOMETRIC); } else if (prompt == BIOMETRIC_PAM_DOUBLE) { m_managerFullScreen->getMainWindow()->setDoubleAuth(true); m_managerFullScreen->getMainWindow()->switchAuthMode(MainWindow::BIOMETRIC); //这时候不需要显示授权弹窗,下一次收到prompt请求的时候再显示 return; } else { unacknowledged_messages = false; m_managerFullScreen->getMainWindow()->switchAuthMode(MainWindow::PASSWORD); m_managerFullScreen->getMainWindow()->setPrompt(prompt, echo); m_managerFullScreen->showDialog(); } } //目前返回的pam错误就onShowError,onShowInfo两类 void PolkitListener::onShowError(const QString &text) { qDebug() << "[Polkit]:" << "Error:" << text; unacknowledged_messages = true; if (m_managerFullScreen && m_managerFullScreen->getMainWindow()) { QString strText = m_managerFullScreen->getMainWindow()->check_is_pam_message(text); m_managerFullScreen->getMainWindow()->setMessage(strText); } } void PolkitListener::onShowInfo(const QString &text) { qDebug() << "[Polkit]:" << "Info:" << text; unacknowledged_messages = true; if (m_managerFullScreen && m_managerFullScreen->getMainWindow()) { QString strText = m_managerFullScreen->getMainWindow()->check_is_pam_message(text); m_managerFullScreen->getMainWindow()->setMessage(strText); } } void PolkitListener::onResponse(const QString &text) { unacknowledged_messages = false; session.data()->setResponse(text); } void PolkitListener::onAuthCompleted(bool gainedAuthorization) { qDebug() << "completed: " << gainedAuthorization; if (m_managerFullScreen) m_managerFullScreen->getMainWindow()->resetSendPassword(); this->gainedAuthorization = gainedAuthorization; finishObtainPrivilege(); } bool PolkitListener::initiateAuthenticationFinish() { qDebug() << "initiateAuthenticationFinish."; return true; } void PolkitListener::cancelAuthentication() { wasCancelled = true; qDebug() << "cancelAuthentication."; finishObtainPrivilege(); } ukui-biometric-auth/polkit-agent/CMakeLists.txt0000664000175000017500000001153315167732644020547 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-polkit-agent) pkg_check_modules(KDKINFO REQUIRED kysdk-sysinfo) pkg_check_modules(KDKWIDGETS REQUIRED kysdk-qtwidgets) pkg_check_modules(KYSDKWAYLANDHELPER REQUIRED kysdk-waylandhelper) pkg_check_modules(KYSDKWINDOWHELPER REQUIRED kysdk-ukuiwindowhelper) # 根据Qt版本查找相应的PolkitQt包 if(QT_VERSION_MAJOR EQUAL 6) pkg_check_modules(QGS REQUIRED gsettings-qt6) find_package(PolkitQt6-1 REQUIRED 0.103.0) find_package(Qt6 COMPONENTS Core Widgets DBus Xml Network Svg) set(POLKITQT_PREFIX PolkitQt6-1) else() pkg_check_modules(QGS REQUIRED gsettings-qt) find_package(PolkitQt5-1 REQUIRED 0.103.0) find_package(Qt5 COMPONENTS Core Widgets DBus X11Extras Xml Network Svg) set(POLKITQT_PREFIX PolkitQt5-1) endif() # 根据Qt版本查找相应的KF包 if(QT_VERSION_MAJOR EQUAL 6) # 尝试查找KF6,如果失败则回退到KF5 find_package(KF6WindowSystem QUIET) if(KF6WindowSystem_FOUND) message(STATUS "Using KF6") set(KF_PREFIX KF6) set(KF_WINDOW_SYSTEM KF6::WindowSystem) else() message(STATUS "KF6 not found, using KF5") find_package(KF5WindowSystem REQUIRED) set(KF_PREFIX KF5) set(KF_WINDOW_SYSTEM KF5::WindowSystem) endif() else() find_package(KF5WindowSystem REQUIRED) set(KF_PREFIX KF5) set(KF_WINDOW_SYSTEM KF5::WindowSystem) endif() find_package(X11 REQUIRED) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) set(LIB_ARCH_PATH /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}) configure_file( ${PROJECT_SOURCE_DIR}/data/polkit-ukui-authentication-agent-1.desktop.in ${PROJECT_BINARY_DIR}/data/polkit-ukui-authentication-agent-1.desktop ) include_directories( ${QGS_INCLUDE_DIRS} ${KDKINFO_INCLUDE_DIRS} ${KDKWIDGETS_INCLUDE_DIRS} ${KYSDKWAYLANDHELPER_INCLUDE_DIRS} ${KYSDKWINDOWHELPER_INCLUDE_DIRS} ) link_directories( ${KDKINFO_LIBRARY_DIRS} ${KDKWIDGETS_LIBRARY_DIRS} ${KYSDKWAYLANDHELPER_LIBRARY_DIRS} ${KYSDKWINDOWHELPER_LIBRARY_DIRS} ) set(EXTRA_LIBS ${EXTRA_LIBS} ${QGS_LIBRARIES} ${KDKINFO_LIBRARIES} ${KDKWIDGETS_LIBRARIES} ${KYSDKWAYLANDHELPER_LIBRARIES} ${KYSDKWINDOWHELPER_LIBRARIES} ) # 根据Qt版本设置包含目录和资源处理 if(QT_VERSION_MAJOR EQUAL 6) include_directories( ${POLKITQT-1_INCLUDE_DIR} ../common ../bioauth/include ) qt6_add_resources(polkit_SRCS assets.qrc) qt6_wrap_ui(polkit_SRCS src/mainwindow.ui ) else() include_directories( ${POLKITQT-1_INCLUDE_DIR} ../common ../bioauth/include ) qt5_add_resources(polkit_SRCS assets.qrc) qt5_wrap_ui(polkit_SRCS src/mainwindow.ui ) endif() set(polkit_SRCS ${polkit_SRCS} src/PolkitAgent.cpp src/mainwindow.cpp src/PolkitListener.cpp src/sessionmanager.cpp src/users.cpp src/pam-tally.c src/modeButton.cpp src/kalabel.cpp ../common/generic.cpp src/fullscreenbackground.h src/fullscreenbackground.cpp src/usdblockshortcut.h src/usdblockshortcut.cpp ) add_executable(polkit-ukui-authentication-agent-1 ${polkit_SRCS}) target_include_directories(polkit-ukui-authentication-agent-1 PRIVATE ${KYSDKQTWIDGETS_PKG_INCLUDE_DIRS}) target_link_directories(polkit-ukui-authentication-agent-1 PRIVATE ${KYSDKQTWIDGETS_PKG_LIBRARY_DIRS}) # 根据Qt版本设置链接库 if(QT_VERSION_MAJOR EQUAL 6) target_link_libraries(polkit-ukui-authentication-agent-1 Qt6::Core Qt6::Widgets Qt6::DBus ${EXTRA_LIBS} ${KF_WINDOW_SYSTEM} ${POLKITQT-1_LIBRARIES} ${KYSDKQTWIDGETS_PKG_LIBRARIES} BioAuthWidgets -lrt -lukui-log4qt ) else() target_link_libraries(polkit-ukui-authentication-agent-1 Qt5::Core Qt5::Widgets Qt5::DBus ${EXTRA_LIBS} ${KF_WINDOW_SYSTEM} ${POLKITQT-1_LIBRARIES} ${KYSDKQTWIDGETS_PKG_LIBRARIES} BioAuthWidgets -lrt -lukui-log4qt ) endif() install(TARGETS polkit-ukui-authentication-agent-1 DESTINATION lib/${CMAKE_LIBRARY_ARCHITECTURE}/ukui-polkit) # 翻译文件 file(GLOB ts_files i18n_ts/*.ts) # 根据Qt版本使用相应的翻译函数 if(QT_VERSION_MAJOR EQUAL 6) qt6_add_translation(qm_files ${ts_files}) else() qt5_add_translation(qm_files ${ts_files}) endif() add_custom_target(polkit_i18n DEPENDS ${qm_files} SOURCES ${ts_files}) add_dependencies(polkit-ukui-authentication-agent-1 polkit_i18n) install(FILES ${qm_files} DESTINATION ${UKUI_BIOMETRIC_DIR}/i18n_qm/polkit) install(FILES ${PROJECT_BINARY_DIR}/data/polkit-ukui-authentication-agent-1.desktop DESTINATION /etc/xdg/autostart) install(FILES ${PROJECT_BINARY_DIR}/data/polkit-ukui-authentication-agent-1.desktop DESTINATION /usr/share/applications) ukui-biometric-auth/polkit-agent/assets/0000775000175000017500000000000015167732644017306 5ustar fengfengukui-biometric-auth/polkit-agent/assets/hide-password.png0000664000175000017500000000051715167732630022563 0ustar fengfengPNG  IHDRĴl;IDAT8ұJQ߷X|@|-TLl%4V2[[JHa'hHk%#R.; cƌMDD\۶^{"b>" 3kf ؃m[9|FUݼpKUi{NmAU=c{|Uqf.V 1ՎqQU3s 3X:.[U=XjU R|yf'`xUkQ݌G{+"6~+bϏ>G`GՎ?(-IENDB`ukui-biometric-auth/polkit-agent/assets/show-password.png0000664000175000017500000000110615167732630022625 0ustar fengfengPNG  IHDRĴl; IDAT8ˋq#a( Q.)?@԰U{\"epye1&e!. Pr f=Nӹ|y~K]Zֈh4Zj Ef"bBD\?z]l~l׸V;xTIhF<Wф \F<8TG1X4h6Eb̓0'U?3_nC\́~ޣRx ډYE~38x<]q3Vefoŷ#b"F|O2/GمKW籪X?-⫑* "b/7Ef.̥ލ؇򽃲3QHJX/J.X.sqg3TujjeDOf +2 .a&VgAߐ4=؁~ ba8_Âk}#+Pf满j/ gIENDB`ukui-biometric-auth/polkit-agent/assets/arrow_down.svg0000664000175000017500000000146415167732630022210 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/0000775000175000017500000000000015167732644021442 5ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris7.svg0000664000175000017500000000266715167732644023233 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/0000775000175000017500000000000015167732644022363 5ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris7.svg0000664000175000017500000000532115167732644024142 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint3.svg0000664000175000017500000004457415167732644025534 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint6.svg0000664000175000017500000001321115167732644025352 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris9.svg0000664000175000017500000000532215167732644024145 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris3.svg0000664000175000017500000000532015167732644024135 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein0.svg0000664000175000017500000002114715167732644025325 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint4.svg0000664000175000017500000001321115167732644025350 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint7.svg0000664000175000017500000001321115167732644025353 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint4.svg0000664000175000017500000005053215167732644025524 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris10.svg0000664000175000017500000000532315167732644024216 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint0.svg0000664000175000017500000003325215167732644025520 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein3.svg0000664000175000017500000002213015167732644025321 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint8.svg0000664000175000017500000007343715167732644025541 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint6.svg0000664000175000017500000005621215167732644025527 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris6.svg0000664000175000017500000000532015167732644024140 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint2.svg0000664000175000017500000004203015167732644025514 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint2.svg0000664000175000017500000001321115167732644025346 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint7.svg0000664000175000017500000006616715167732644025542 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris5.svg0000664000175000017500000000532115167732644024140 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein11.svg0000664000175000017500000002213515167732644025405 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein2.svg0000664000175000017500000002213015167732644025320 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint0.svg0000664000175000017500000001321115167732644025344 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint5.svg0000664000175000017500000005234115167732644025525 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein6.svg0000664000175000017500000002213015167732644025324 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint11.svg0000664000175000017500000010372015167732644025600 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris2.svg0000664000175000017500000000532015167732644024134 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein4.svg0000664000175000017500000002213115167732644025323 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint14.svg0000664000175000017500000003626215167732644025611 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint10.svg0000664000175000017500000010117215167732644025576 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris0.svg0000664000175000017500000000433515167732644024137 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein5.svg0000664000175000017500000002213115167732644025324 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint9.svg0000664000175000017500000007651315167732644025540 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint12.svg0000664000175000017500000010551515167732644025605 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint5.svg0000664000175000017500000001321115167732644025351 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris8.svg0000664000175000017500000000532215167732644024144 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris4.svg0000664000175000017500000000532115167732644024137 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein9.svg0000664000175000017500000002213215167732644025331 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint1.svg0000664000175000017500000001321115167732644025345 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint13.svg0000664000175000017500000011013715167732644025602 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein8.svg0000664000175000017500000002213215167732644025330 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/voiceprint3.svg0000664000175000017500000001321115167732644025347 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingerprint1.svg0000664000175000017500000004101715167732644025517 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein1.svg0000664000175000017500000002210415167732644025320 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein7.svg0000664000175000017500000002213115167732644025326 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris11.svg0000664000175000017500000000532315167732644024217 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/iris1.svg0000664000175000017500000000527415167732644024143 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/dark/fingervein10.svg0000664000175000017500000002213315167732644025402 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint3.svg0000664000175000017500000002214415167732644024600 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint6.svg0000664000175000017500000001321115167732644024431 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris9.svg0000664000175000017500000000267215167732644023231 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris3.svg0000664000175000017500000000266715167732644023227 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein0.svg0000664000175000017500000000527615167732644024411 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint4.svg0000664000175000017500000001321115167732644024427 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint7.svg0000664000175000017500000001321115167732644024432 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint4.svg0000664000175000017500000002347015167732644024604 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris10.svg0000664000175000017500000000267215167732644023301 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint0.svg0000664000175000017500000001763415167732644024605 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein3.svg0000664000175000017500000000613715167732644024411 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint8.svg0000664000175000017500000003274315167732644024613 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint6.svg0000664000175000017500000002556115167732644024611 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris6.svg0000664000175000017500000000266715167732644023232 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint2.svg0000664000175000017500000002115315167732644024576 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint2.svg0000664000175000017500000001321115167732644024425 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint7.svg0000664000175000017500000003057115167732644024607 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris5.svg0000664000175000017500000000266715167732644023231 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein11.svg0000664000175000017500000000614215167732644024464 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein2.svg0000664000175000017500000000613715167732644024410 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint0.svg0000664000175000017500000001321115167732644024423 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint5.svg0000664000175000017500000002420715167732644024604 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein6.svg0000664000175000017500000000613715167732644024414 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint11.svg0000664000175000017500000003574115167732644024666 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris2.svg0000664000175000017500000000266715167732644023226 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein4.svg0000664000175000017500000000613715167732644024412 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint14.svg0000664000175000017500000001762615167732644024673 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint10.svg0000664000175000017500000003471015167732644024660 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris0.svg0000664000175000017500000000202615167732644023211 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein5.svg0000664000175000017500000000613715167732644024413 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint9.svg0000664000175000017500000003374615167732644024620 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint12.svg0000664000175000017500000003647015167732644024667 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint5.svg0000664000175000017500000001321115167732644024430 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris8.svg0000664000175000017500000000267115167732644023227 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris4.svg0000664000175000017500000000266715167732644023230 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein9.svg0000664000175000017500000000614215167732644024413 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint1.svg0000664000175000017500000001321115167732644024424 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint13.svg0000664000175000017500000003754415167732644024673 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein8.svg0000664000175000017500000000614115167732644024411 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/voiceprint3.svg0000664000175000017500000001321115167732644024426 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingerprint1.svg0000664000175000017500000002071315167732644024576 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein1.svg0000664000175000017500000000613715167732644024407 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein7.svg0000664000175000017500000000613715167732644024415 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris11.svg0000664000175000017500000000267215167732644023302 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/iris1.svg0000664000175000017500000000266715167732644023225 0ustar fengfengukui-biometric-auth/polkit-agent/assets/biowaiting/fingervein10.svg0000664000175000017500000000614215167732644024463 0ustar fengfengukui-biometric-auth/polkit-agent/assets/arrow_right.svg0000664000175000017500000000124615167732630022354 0ustar fengfengukui-biometric-auth/polkit-agent/assets.qrc0000664000175000017500000001277715167732644020033 0ustar fengfeng assets/arrow_down.svg assets/arrow_right.svg assets/hide-password.png assets/show-password.png assets/biowaiting/fingerprint0.svg assets/biowaiting/fingerprint1.svg assets/biowaiting/fingerprint2.svg assets/biowaiting/fingerprint3.svg assets/biowaiting/fingerprint4.svg assets/biowaiting/fingerprint5.svg assets/biowaiting/fingerprint6.svg assets/biowaiting/fingerprint7.svg assets/biowaiting/fingerprint8.svg assets/biowaiting/fingerprint9.svg assets/biowaiting/fingerprint10.svg assets/biowaiting/fingerprint11.svg assets/biowaiting/fingerprint12.svg assets/biowaiting/fingerprint13.svg assets/biowaiting/fingerprint14.svg assets/biowaiting/fingervein0.svg assets/biowaiting/fingervein1.svg assets/biowaiting/fingervein2.svg assets/biowaiting/fingervein3.svg assets/biowaiting/fingervein4.svg assets/biowaiting/fingervein5.svg assets/biowaiting/fingervein6.svg assets/biowaiting/fingervein7.svg assets/biowaiting/fingervein8.svg assets/biowaiting/fingervein9.svg assets/biowaiting/fingervein10.svg assets/biowaiting/fingervein11.svg assets/biowaiting/iris0.svg assets/biowaiting/iris1.svg assets/biowaiting/iris2.svg assets/biowaiting/iris3.svg assets/biowaiting/iris4.svg assets/biowaiting/iris5.svg assets/biowaiting/iris6.svg assets/biowaiting/iris7.svg assets/biowaiting/iris8.svg assets/biowaiting/iris9.svg assets/biowaiting/iris10.svg assets/biowaiting/iris11.svg assets/biowaiting/voiceprint0.svg assets/biowaiting/voiceprint1.svg assets/biowaiting/voiceprint2.svg assets/biowaiting/voiceprint3.svg assets/biowaiting/voiceprint4.svg assets/biowaiting/voiceprint5.svg assets/biowaiting/voiceprint6.svg assets/biowaiting/voiceprint7.svg assets/biowaiting/dark/fingerprint0.svg assets/biowaiting/dark/fingerprint1.svg assets/biowaiting/dark/fingerprint2.svg assets/biowaiting/dark/fingerprint3.svg assets/biowaiting/dark/fingerprint4.svg assets/biowaiting/dark/fingerprint5.svg assets/biowaiting/dark/fingerprint6.svg assets/biowaiting/dark/fingerprint7.svg assets/biowaiting/dark/fingerprint8.svg assets/biowaiting/dark/fingerprint9.svg assets/biowaiting/dark/fingerprint10.svg assets/biowaiting/dark/fingerprint11.svg assets/biowaiting/dark/fingerprint12.svg assets/biowaiting/dark/fingerprint13.svg assets/biowaiting/dark/fingerprint14.svg assets/biowaiting/dark/fingervein0.svg assets/biowaiting/dark/fingervein1.svg assets/biowaiting/dark/fingervein2.svg assets/biowaiting/dark/fingervein3.svg assets/biowaiting/dark/fingervein4.svg assets/biowaiting/dark/fingervein5.svg assets/biowaiting/dark/fingervein6.svg assets/biowaiting/dark/fingervein7.svg assets/biowaiting/dark/fingervein8.svg assets/biowaiting/dark/fingervein9.svg assets/biowaiting/dark/fingervein10.svg assets/biowaiting/dark/fingervein11.svg assets/biowaiting/dark/iris0.svg assets/biowaiting/dark/iris1.svg assets/biowaiting/dark/iris2.svg assets/biowaiting/dark/iris3.svg assets/biowaiting/dark/iris4.svg assets/biowaiting/dark/iris5.svg assets/biowaiting/dark/iris6.svg assets/biowaiting/dark/iris7.svg assets/biowaiting/dark/iris8.svg assets/biowaiting/dark/iris9.svg assets/biowaiting/dark/iris10.svg assets/biowaiting/dark/iris11.svg assets/biowaiting/dark/voiceprint0.svg assets/biowaiting/dark/voiceprint1.svg assets/biowaiting/dark/voiceprint2.svg assets/biowaiting/dark/voiceprint3.svg assets/biowaiting/dark/voiceprint4.svg assets/biowaiting/dark/voiceprint5.svg assets/biowaiting/dark/voiceprint6.svg assets/biowaiting/dark/voiceprint7.svg src/main.qss ukui-biometric-auth/polkit-agent/i18n_ts/0000775000175000017500000000000015167732644017271 5ustar fengfengukui-biometric-auth/polkit-agent/i18n_ts/ru.ts0000664000175000017500000002362415167732644020276 0ustar fengfeng BioAuthWidget Form форма BioDevicesWidget Form форма FullScreenBackground Authentication Аутентификация MainWindow Form форма Biometric Биометрические Details Детали Polkit.subject-pid: Polkit.subject-PID: Vendor: Производитель: Description: Описание: Polkit.caller-pid: Polkit.caller-PID: Action: Действие: Cancel Отмена Authenticate проверять подлинность Authentication Аутентификация in authentication, please wait... в аутентификации, пожалуйста, подождите ... An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. Приложение пытается выполнить действие, требующее привилегий. Для выполнения этого действия требуется аутентификация. Password: Пароль: Authentication failed, please try again. Ошибка аутентификации. Пожалуйста, попробуйте еще раз. Please enter your password or enroll your fingerprint use password Account locked, days left hours left minutes left seconds left Password cannot be empty Use password Please try again in %1 minutes. Please try again in %1 seconds. Account locked permanently. Failed to verify %1, you still have %2 verification opportunities Input Password Failed to verify %1, please enter password to unlock Unable to verify %1, please enter password to unlock A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. _Password: _Password: Abnormal network This operation requires the administrator's authorization. Please enter your password to allow this operation. Insert the ukey into the USB port Enter the ukey password Input your password to authentication Close Acquisition failure Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" wechat Use the bound %1 scanning code to authorization PolkitListener Another client is already authenticating, please try again later. Другой клиент уже аутентифицируется, повторите попытку позже. Authentication failure, please try again. Ошибка аутентификации, повторите попытку. Password input error! QObject Cancel Отмена ukui-biometric-auth/polkit-agent/i18n_ts/de.ts0000664000175000017500000005355115167732644020242 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication Authentifizierung LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication Authentifizierung Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form More 更多 Restart 重新开始 Password 密码 Biometric Biometrisch use password Passwort verwenden DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel Abbrechen Authenticate Beglaubigen Use password Passwort verwenden Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. Versuchen Sie es in %1 Minuten erneut. Please try again in %1 seconds. Bitte versuchen Sie es in %1 Sekunden erneut. Account locked permanently. Das Konto wurde dauerhaft gesperrt. Password cannot be empty Das Kennwort darf nicht leer sein. Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities %1 konnte nicht verifiziert werden, Sie haben immer noch %2 Überprüfungsmöglichkeiten An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: Passwort: Please enter your password or enroll your fingerprint Bitte geben Sie Ihr Passwort ein oder registrieren Sie Ihren Fingerabdruck wechat Use the bound %1 scanning code to authorization Abnormal network Ungewöhnliches Netzwerk This operation requires the administrator's authorization. Please enter your password to allow this operation. Für diesen Vorgang ist die Autorisierung des Administrators erforderlich. Bitte geben Sie Ihr Passwort ein, um diesen Vorgang zuzulassen. _Password: _Passwort: _Password: _Passwort: Authentication failed, please try again. Authentifizierung fehlgeschlagen, bitte versuchen Sie es erneut. days left Verbleibende Tage Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock %1 konnte nicht verifiziert werden, bitte geben Sie das Kennwort zum Entsperren ein Unable to verify %1, please enter password to unlock %1 kann nicht verifiziert werden, bitte geben Sie das Kennwort zum Entsperren ein NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. Ein Programm versucht, eine Aktion auszuführen, für die Berechtigungen erforderlich sind. Zum Ausführen der Aktion ist eine Autorisierung erforderlich. Input Password Passwort eingeben Insert the ukey into the USB port Enter the ukey password Close Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Acquisition failure hours left Verbleibende Stunden minutes left Noch Minuten seconds left Verbleibende Sekunden Input your password to authentication Verify face recognition or enter password to unlock Überprüfen Sie die Gesichtserkennung oder geben Sie das Passwort ein, um zu entsperren Press fingerprint or enter password to unlock Drücken Sie den Fingerabdruck oder geben Sie das Passwort ein, um zu entsperren Verify voiceprint or enter password to unlock Überprüfen Sie den Stimmabdruck oder geben Sie das Passwort ein, um zu entsperren Verify finger vein or enter password to unlock Überprüfen Sie die Fingervene oder geben Sie das Passwort ein, um zu entsperren Verify iris or enter password to unlock Überprüfen Sie die Iris oder geben Sie das Passwort ein, um zu entsperren Use the bound wechat scanning code or enter the password to unlock Verwenden Sie den gebundenen Wechat-Scan-Code oder geben Sie das Passwort zum Entsperren ein Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, Konto gesperrt, Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. Ein anderer Client authentifiziert sich bereits, bitte versuchen Sie es später noch einmal. Authentication failure, please try again. Authentifizierungsfehler, bitte versuchen Sie es erneut. Password input error! Fehler bei der Passworteingabe! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/ky.ts0000664000175000017500000005646315167732644020302 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication راستىنى دالىلدۅ LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication راستىنى دالىلدۅ Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form جادىبال More 更多 Restart 重新开始 Password 密码 Biometric بىئولەگىيەلىك ۅزگۅچۅلۉگۉ ىشتەتىش use password جاشىرۇۇن نومۇر ىشتەتىش DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel ارعادان قالتىرىش Authenticate ۇقۇق بەرۉۉ Use password جاشىرۇۇن نومۇر ىشتەتىش ارقىلۇۇ دالىلدۅ Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. ٪1 مىنۇت ىچىندە قايرا سىناپ باعىڭ. Please try again in %1 seconds. ٪1 سىكونت ىچىندە قايرا سىناپ باعىڭ. Account locked permanently. ەسابات تۉبۅلۉك قۇلۇپلىنىدۇ. Password cannot be empty جاشىرۇۇن نومۇردۇ بوش ،بەكەر قويۇشقا بولبويت Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities ٪1 نى دالىلدۅ جەڭىلۉۉ بولدۇ ، سىزدە داعى ەلە ٪2 دالىلدۅ مۅۅرتۉ بار An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: جاشىرۇۇن نومۇر Please enter your password or enroll your fingerprint جاشىرۇۇن نومۇرۇڭۇزدۇ كىرگىزىڭ كۅرۉنۉشتۅرۉ بارماق ئىزىڭىزنى تونۇتۇڭ wechat Use the bound %1 scanning code to authorization Abnormal network بۅتۅنچۅ تور This operation requires the administrator's authorization. Please enter your password to allow this operation. بۇل ماشقۇلدانۇۇ باشقارۇۇچۇنۇن ۇقۇق بەرۉۉنۉ تالاپ جاسايت .جاشىرۇۇن نومۇردۇ كىيىرىپ بي قاتىمقى ماشقۇلدانۇۇ نىڭ الىپ بېرىلىشىغا جول قويۇڭ. _Password: جاشىرۇۇن نومۇر _Password: جاشىرۇۇن نومۇر Authentication failed, please try again. دالىلدۅ جەڭىلۉۉ بولدۇ ، قايرا سىناڭ days left 1 كۉندۅن كىيىن سىناپ باعىڭ Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock ٪1 نى دالىلدۅ جەڭىلۉۉ بولدۇ ، سىرلۇۇ نومۇر كىرگىزىڭ Unable to verify %1, please enter password to unlock ٪1 نى دالىلدۅۅگۅ ايلاسىز، جاشىرۇۇن نومۇردۇ كىيىرىپ قۇلۇپنى اچىڭ NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. بىر پراگرامما ۇقۇق تالاپ جاسايتۇرعان قىيمىلدى جاسووعو ئۇرۇنماقتا. بۇل قىيمىلدى اتقارماق جاسوو ،اتقارۇۇ ۉچۉن ۇقۇق تالاپ جاسايت . Input Password جاشىرۇۇن نومۇر كىرگىزۉۉ Insert the ukey into the USB port ukey نى USB ووزۇنا چېتىپ قويۇڭ Enter the ukey password ukey جاشىرۇۇن نومۇرۇن كىرگىزىڭ Close Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Acquisition failure hours left بىر سائەتتىن كىيىن اچىلات minutes left بىر مىنۇتتان كىيىن اچىلات seconds left بىر سەكۇنتتان كىيىن اچىلات Input your password to authentication جاشىرۇۇن نومۇردۇ كىيىرىپ كۉبۅلۉك دالىلدۅ. Verify face recognition or enter password to unlock چىراي تاانىشتى دالىلدۅ كۅرۉنۉشتۅرۉ جاشىرۇۇن نومۇر كىرگىزۉۉ ارقىلۇۇ قۇلپ اچۇۇ Press fingerprint or enter password to unlock بارماق ىزىن باسۇۇدا كۅرۉنۉشتۅرۉ جاشىرۇۇن نومۇر كىرگىزۉۉ ارقىلۇۇ قۇلپ اچۇۇ Verify voiceprint or enter password to unlock دووش ىزىن دالىلدۅ كۅرۉنۉشتۅرۉ جاشىرۇۇن نومۇر كىرگىزۉۉ ارقىلۇۇ قۇلپ اچۇۇ Verify finger vein or enter password to unlock بارماق ئزى ارقىلۇۇ انىقتاش كۅرۉنۉشتۅرۉ جاشىرۇۇن نومۇر كىرگىزۉۉ ارقىلۇۇ قۇلپ اچۇۇ Verify iris or enter password to unlock Iris نى انىقتاش كۅرۉنۉشتۅرۉ جاشىرۇۇن نومۇر كىرگىزۉۉ ارقىلۇۇ قۇلپ اچۇۇ Use the bound wechat scanning code or enter the password to unlock بايلانعان ئۈندىدارنى ىسكاننىردوو قۇپۇيا نومۇرۇ كۅرۉنۉشتۅرۉ جاشىرۇۇن نومۇرۇن كىيىرىپ قۇلپ اچۇۇ Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, ىشتەتىش نومۇرۇڭۇز قۇلۇپتالىپ قالدى Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. داعى بىر سووداگەر ، جولووچۇ دالىلدەپ جاتات، سەل تۇرۇپ قايرا سىناڭ. Authentication failure, please try again. دالىلدۅ جەڭىلۉۉ بولدۇ ، قايرا سىناڭ. Password input error! كىيىرگەن جاشىرۇۇن نومۇر قاتاا بولدۇ Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/zh_CN.ts0000664000175000017500000005263315167732644020653 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication 授权 LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication 授权 Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form More 更多 Restart 重新开始 Password 密码 Biometric 使用生物识别 use password 使用密码验证 DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel 取消 Authenticate 授权 Use password 使用密码验证 Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. 请%1分钟后再试 Please try again in %1 seconds. 请%1秒后再试 Account locked permanently. 账号已被永久锁定 Password cannot be empty 密码不能为空 Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities 验证%1失败,您还有%2次尝试机会 An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: 密码: Please enter your password or enroll your fingerprint 请输入密码或者录入指纹 wechat 微信 Use the bound %1 scanning code to authorization %1扫码以授权 Abnormal network 网络异常 This operation requires the administrator's authorization. Please enter your password to allow this operation. 本次操作需要通过管理员的授权才能继续执行,请输入密码以允许本次操作。 _Password: 密码: _Password: 密码: Authentication failed, please try again. 认证失败,请重试。 days left 天后解锁 Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock 验证%1失败,请输入密码解锁 Unable to verify %1, please enter password to unlock 无法验证%1,请输入密码解锁 NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. 一个程序正试图执行一个需要特权的动作,要求授权以执行该动作。 Input Password 输入密码 Insert the ukey into the USB port 请将安全密钥插入USB端口 Enter the ukey password 输入安全密钥密码 Close 关闭 Enter the two-factor authentication (2FA) OTP token for the administrator "%1" 输入管理员"%1"双因子认证OTP动态口令 Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" 输入管理员"%1"双因子认证OTP动态口令 Enter the two-factor authentication (2FA) security key for the administrator "%1" 输入管理员"%1"双因子认证安全密钥 Enter the two-factor authentication (2FA) security key for the user "%1" 输入用户"%1"双因子认证安全密钥 Facial recognition to authorization 识别人脸以授权 Fingerprint recognition to authorization 识别指纹以授权 Voiceprint recognition to authorization 识别声纹以授权 Finger veins recognition to authorization 识别指静脉以授权 Iris recognition to authorization 识别虹膜以授权 Use the bound wechat scanning code to authorization 微信扫码以授权 Acquisition failure 获取失败 hours left 小时后解锁 minutes left 分钟后解锁 seconds left 秒后解锁 Input your password to authentication 输入密码以授权 Verify face recognition or enter password to unlock 验证人脸识别或输入密码解锁 Press fingerprint or enter password to unlock 按压指纹或输入密码解锁 Verify voiceprint or enter password to unlock 验证声纹或输入密码解锁 Verify finger vein or enter password to unlock 验证指静脉或输入密码解锁 Verify iris or enter password to unlock 验证虹膜或输入密码解锁 Use the bound wechat scanning code or enter the password to unlock 使用绑定的微信扫码或输入密码解锁 Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, 账户已锁定, Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. 有另外一个客户端正在认证,请稍后重试。 Authentication failure, please try again. 认证失败,请重试。 Password input error! 密码输入错误! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/kk.ts0000664000175000017500000005573615167732644020266 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication شىندىقتى دالەلدەۋ LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication شىندىقتى دالەلدەۋ Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form كەستە More 更多 Restart 重新开始 Password 密码 Biometric بىئولەگىيەلىك ەرەكشەلىكتى ٸستەتۋ use password قۇپيا نومەر ٸستەتۋ DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel كۇشىنەن قالدىرۋ Authenticate ۇقىق بەرۋ Use password قۇپيا نومەر ٸستەتۋ ارقىلى دالەلدەۋ Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. ٪1 مينۋت ٸشٸندە قاتە سىناپ كور. Please try again in %1 seconds. ٪1 سەكونت ٸشٸندە قاتە سىناپ كور. Account locked permanently. ەسەپات ماڭگىلىك قۇلىپتالادى. Password cannot be empty قۇپيا نۇمىردى بوس قويۋعا بولمايدى Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities ٪1 نى دالەلدەۋ جەڭىلىپ قالدى، سىزدە جانەدە ٪2 دالەلدەۋ ورايى بار An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: قۇپيا نومەر Please enter your password or enroll your fingerprint قۇپيا نۇمىرىڭىزدى كىرگىزىڭىز ياكي بارماقشى ئىزىڭىزنى تونۇتۇڭ wechat Use the bound %1 scanning code to authorization Abnormal network بينورمال تور This operation requires the administrator's authorization. Please enter your password to allow this operation. نۇ جوبالاۋ باسقارعٸشتٸڭ ۇقىق بىرىستى تالاپ ىستەيدى.قۇپيا نۇمىردى كىرەۈزۈپ بي رەتكى جوبالاۋنىڭ الىپ بېرىلىشىغا جول قويىڭىز. _Password: قۇپيا نومەر _Password: قۇپيا نومەر Authentication failed, please try again. دالەلدەۋ جەڭىلىپ قالدى، قاتە سىناڭ days left 1 كۇننەن كەيىن سناپ كور Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock ٪1 نى دالەلدەۋ جەڭىلىپ قالدى، قۇپيا نومەر كىرگىزىڭىز Unable to verify %1, please enter password to unlock ٪1 نى دالەلدەۋگە امالسٸز، قۇپيا نۇمىردى كىرەۈزۈپ قۇلىبىن ٴٸشڭٸز NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. بٸر پٸروگٸرامما ۇقىق تالاپ ىستەيتىن ارەكەتتى ىستەۋگە ئۇرۇنماقتا. نۇ ارەكەتتى اتقار ەتۋ ٷشٸن ۇقىق تالاپ ىستەيدى. Input Password قۇپيا نومەر كىرگىزۋ Insert the ukey into the USB port ukey نى USB اۋزىنا چېتىپ قويىڭىز Enter the ukey password ukey قۇپيا نۇمىردى كىرگىزىڭىز Close Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Acquisition failure hours left بٸر ساعاتتان كەيىن اشٸلدٸ minutes left بٸر مينوتتىن كەيىن اشٸلدٸ seconds left بٸر سەكونتىن كەيىن اشٸلدٸ Input your password to authentication قۇپيا نۇمىردى كىرەۈزۈپ ازاماتتىق كۋالىك دالەلدەۋ. Verify face recognition or enter password to unlock چىراي تانىسن دالەلدەۋ ياكي قۇپيا نومەر كىرگىزۋ ارقىلى قۇلىپ ٸشٸۋ Press fingerprint or enter password to unlock بارماقشى ٴٸزدٸ باسٸۋ ياكي قۇپيا نومەر كىرگىزۋ ارقىلى قۇلىپ ٸشٸۋ Verify voiceprint or enter password to unlock اۋا ٴٸزدٸ دالەلدەۋ ياكي قۇپيا نومەر كىرگىزۋ ارقىلى قۇلىپ ٸشٸۋ Verify finger vein or enter password to unlock بارماقشى ٴٸزٸ ارقىلى انىقتاۋ ياكي قۇپيا نومەر كىرگىزۋ ارقىلى قۇلىپ ٸشٸۋ Verify iris or enter password to unlock Iris نى انىقتاۋ ياكي قۇپيا نومەر كىرگىزۋ ارقىلى قۇلىپ ٸشٸۋ Use the bound wechat scanning code or enter the password to unlock بايلانعان ئۈندىدارنى كەسكىندەۋ بەلگىسى ياكي قۇپيا نۇمىردى كىرەۈزۈپ قۇلىپ ٸشٸۋ Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, ٸستەتۋ نومەرىڭىز قۇلىپتانىپ قالدى Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. جانە بٸر قاريدار دالەلدەپ جاتىر، سەل تۇرٸپ قاتە سىناڭ. Authentication failure, please try again. دالەلدەۋ جەڭىلىپ قالدى، قاتە سىناڭ. Password input error! كىرگىزگەن قۇپيا نومەر قاتە قالدى Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/tr.ts0000664000175000017500000004167615167732644020304 0ustar fengfeng BioAuthWidget Retry Yeniden Dene BioDevices FingerPrint Parmak İzi FingerVein Damar İzi Iris Göz Face Yüz Tanıma VoicePrint Ses İzi FullScreenBackground Authentication Kimlik Doğrulama MainWindow Authentication Kimlik Doğrulama Failed to verify %1, please enter password to unlock Unable to verify %1, please enter password to unlock wechat Use the bound %1 scanning code to authorization Failed to verify %1, you still have %2 verification opportunities Abnormal network This operation requires the administrator's authorization. Please enter your password to allow this operation. A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. Input Password Insert the ukey into the USB port Enter the ukey password Close Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Acquisition failure Account locked, days left hours left minutes left seconds left Password cannot be empty Input your password to authentication Use password Please try again in %1 minutes. Please try again in %1 seconds. Account locked permanently. Form More Daha Fazla Restart Yeniden Başlat Password Parola Biometric Biyometrik DeviceType: Aygıt Türü: Back Geri Details Ayrıntılar Action Id: İşlem Kimliği: Description: Açıklama: Polkit.subject-pid: Polkit.subject-pid: Retry Yeniden Dene Device types: Aygıt türü: Vendor: Vendor: Action: Eylem: Polkit.caller-pid: Polkit.caller-pid: Cancel İptal Authenticate Kimlik Doğrulaması use password Auth Kimlik Doğrulaması Please enter your password or enroll your fingerprint in authentication, please wait... kimlik doğrulanırken lütfen bekleyin ... An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. Bir uygulama, ayrıcalıklar gerektiren bir eylem gerçekleştirmeye çalışıyor. Bu işlemi gerçekleştirmek için kimlik doğrulaması gerekiyor. Password: Parola: _Password: _Parola: _Password: _Parola: Authentication failed, please try again. Kimlik doğrulama başarısız, lütfen tekrar deneyin. Authentication failed, please try again Kimlik doğrulama başarısız, lütfen tekrar deneyin PolkitListener Another client is already authenticating, please try again later. Başka bir hesap zaten kimlik doğrulaması yapıyor, lütfen daha sonra tekrar deneyin. Authentication failure, please try again. Kimlik doğrulama hatalı, lütfen tekrar deneyin. Password input error! Account locked %1 minutes due to %2 fail attempts %2 başarısız denemeden dolayı hesap %1 dakika kilitlendi Authentication failure,there are still %1 remaining opportunities Kimlik doğrulama hatası, %1 hakkınız kaldı QObject FingerPrint Parmak İzi FingerVein Damar İzi Iris Göz Face Yüz Tanıma VoicePrint Ses İzi Cancel İptal ukui-biometric-auth/polkit-agent/i18n_ts/bo.ts0000664000175000017500000002775515167732644020261 0ustar fengfeng FullScreenBackground Authentication MainWindow Form Biometric use password Cancel Authenticate Insert the ukey into the USB port Enter the ukey password Close Failed to verify %1, please enter password to unlock Unable to verify %1, please enter password to unlock Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Failed to verify %1, you still have %2 verification opportunities Acquisition failure Please enter your password or enroll your fingerprint This operation requires the administrator's authorization. Please enter your password to allow this operation. A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. Password: _Password: _Password: Account locked, days left hours left minutes left seconds left Password cannot be empty Input your password to authentication Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Use password Please try again in %1 minutes. Please try again in %1 seconds. Account locked permanently. Input Password wechat Use the bound %1 scanning code to authorization Abnormal network Authentication failed, please try again. PolkitListener Another client is already authenticating, please try again later. Authentication failure, please try again. Password input error! ukui-biometric-auth/polkit-agent/i18n_ts/ug.ts0000664000175000017500000005614515167732644020267 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication راستىنى دەلىللەش LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication راستىنى دەلىللەش Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form جەدۋەل More 更多 Restart 重新开始 Password 密码 Biometric بىئولەگىيەلىك ئالاھىدىلىكنى ئىشلىتىش use password مەخپىي نومۇر ئىشلىتىش DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel ئەمەلدىن قالدۇرۇش Authenticate ھوقۇق بېرىش Use password مەخپىي نومۇر ئىشلىتىش ئارقىلىق دەلىللەش Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. ٪1 مىنۇت ئىچىدە قايتا سىناپ بېقىڭ. Please try again in %1 seconds. ٪1 سېكۇنت ئىچىدە قايتا سىناپ بېقىڭ. Account locked permanently. ھېسابات مەڭگۈلۈك قۇلۇپلىنىدۇ. Password cannot be empty مەخپىي نومۇرنى بوش قويۇشقا بولمايدۇ Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities ٪1 نى دەلىللەش مەغلۇپ بولدى، سىزدە يەنىلا ٪2 دەلىللەش پۇرسىتى بار An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: مەخپىي نومۇر Please enter your password or enroll your fingerprint مەخپىي نومۇرىڭىزنى كىرگۈزۈڭ ياكى بارماق ئىزىڭىزنى تونۇتۇڭ wechat Use the bound %1 scanning code to authorization Abnormal network بىنورمال تور This operation requires the administrator's authorization. Please enter your password to allow this operation. بۇ مەشغۇلات باشقۇرغۇچىنىڭ ھوقۇق بېرىشىنى تەلەپ قىلىدۇ.مەخپىي نومۇرنى كىرگۈزۈپ بي قېتىمقى مەشغۇلاتنىڭ ئېلىپ بېرىلىشىغا يول قويۇڭ. _Password: مەخپىي نومۇر _Password: مەخپىي نومۇر Authentication failed, please try again. دەلىللەش مەغلۇپ بولدى، قايتا سىناڭ days left 1 كۈندىن كېيىن سىناب بېقىڭ Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock ٪1 نى دەلىللەش مەغلۇپ بولدى، مەخپى نۇمۇر كىرگۈزۈڭ Unable to verify %1, please enter password to unlock ٪1 نى دەلىللەشكە ئامالسىز، مەخپىي نومۇرنى كىرگۈزۈپ قۇلۇپنى ئېچىڭ NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. بىر پروگرامما ئىمتىياز تەلەپ قىلىدىغان ھەرىكەتنى قىلىشقا ئۇرۇنماقتا. بۇ ھەرىكەتنى ئىجرا قىلىش ئۈچۈن ھوقۇق تەلەپ قىلىدۇ. Input Password ئىم كىرگۈزۈش Insert the ukey into the USB port ukey نى USB ئېغىزىغا چېتىپ قويۇڭ Enter the ukey password ukey مەخپىي نومۇرىنى كىرگۈزۈڭ Close Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Acquisition failure hours left بىر سائەتتىن كېيىن ئېچىلىدۇ minutes left بىر مىنۇتتىن كېيىن ئېچىلىدۇ seconds left بىر سېكۇنتتىن كېيىن ئېچىلىدۇ Input your password to authentication مەخپىي نومۇرنى كىرگۈزۈپ كىملىك دەلىللەش. Verify face recognition or enter password to unlock چىراي تونۇشنى دەلىللەش ياكى مەخپىي نومۇر كىرگۈزۈش ئارقىلىق قۇلۇپ ئېچىش Press fingerprint or enter password to unlock بارماق ئىزىنى بېسىش ياكى مەخپىي نومۇر كىرگۈزۈش ئارقىلىق قۇلۇپ ئېچىش Verify voiceprint or enter password to unlock ئاۋاز ئىزىنى دەلىللەش ياكى مەخپىي نومۇر كىرگۈزۈش ئارقىلىق قۇلۇپ ئېچىش Verify finger vein or enter password to unlock بارماق ئىزى ئارقىلىق ئېنىقلاش ياكى مەخپىي نومۇر كىرگۈزۈش ئارقىلىق قۇلۇپ ئېچىش Verify iris or enter password to unlock Iris نى ئېنىقلاش ياكى مەخپىي نومۇر كىرگۈزۈش ئارقىلىق قۇلۇپ ئېچىش Use the bound wechat scanning code or enter the password to unlock باغلانغان ئۈندىدارنى سىكاننېرلاش كودى ياكى مەخپىي نومۇرىنى كىرگۈزۈپ قۇلۇپ ئېچىش Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, ئىشلىتىش نومۇرىڭىز قۇلۇپلىنىپ قالدى Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. يەنە بىر خېرىدار دەلىللەۋاتىدۇ، سەل تۇرۇپ قايتا سىناڭ. Authentication failure, please try again. دەلىللەش مەغلۇپ بولدى، قايتا سىناڭ. Password input error! كىرگۈزگەن مەخپىي نومۇر خاتا بولدى Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/pt.ts0000664000175000017500000002303615167732644020270 0ustar fengfeng BioAuthWidget Form Formato BioDevicesWidget Form Formato FullScreenBackground Authentication Autenticação MainWindow Form Formato Biometric Biométrico Details Detalhes Polkit.subject-pid: Polkit.subject-pid: Vendor: Fornecedor: Description: Descrição: Polkit.caller-pid: Polkit.caller-pid: Action: Açao: Cancel Cancelar Authenticate Autenticar Authentication Autenticação in authentication, please wait... na autenticação, por favor aguarde ... An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. Um aplicativo está tentando executar uma ação que requer privilégios. A autenticação é necessária para executar esta ação. Password: Senha: Authentication failed, please try again. Autenticação falhou. Por favor, tente novamente. Please enter your password or enroll your fingerprint use password Account locked, days left hours left minutes left seconds left Password cannot be empty Use password Please try again in %1 minutes. Please try again in %1 seconds. Account locked permanently. Failed to verify %1, you still have %2 verification opportunities Input Password Failed to verify %1, please enter password to unlock Unable to verify %1, please enter password to unlock A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. _Password: _Password: Abnormal network This operation requires the administrator's authorization. Please enter your password to allow this operation. Insert the ukey into the USB port Enter the ukey password Input your password to authentication Close Acquisition failure Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" wechat Use the bound %1 scanning code to authorization PolkitListener Another client is already authenticating, please try again later. Outro cliente já está autenticando, por favor, tente novamente mais tarde. Authentication failure, please try again. Falha de autenticação, por favor, tente novamente. Password input error! QObject Cancel Cancelar ukui-biometric-auth/polkit-agent/i18n_ts/bo_CN.ts0000664000175000017500000006446715167732644020642 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication བདེན་དཔང་ར་སྤྲོད། LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication དབང་བསྐུར། Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form རེའུ་མིག More 更多 Restart 重新开始 Password 密码 Biometric སྐྱེ་དངོས་སྒྲིག་ཆས། use password གསང་གྲངས་སྤྱད་དེ་བཤེར་དགོས། DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel ཕྱིར་འཐེན། Authenticate བདེན་དཔང་ར་སྤྲོད་བྱ་དགོས Use password གསང་གྲངས་སྤྱད་དེ་བཤེར་དགོས། Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. སྐར་མ་%1འགོར་རྗེས་ཡང་བསྐྱར་ཚོད་ལྟ་བྱས། Please try again in %1 seconds. དུས་ཚོད་སྐར་ཆ་%1འགོར་རྗེས་ཡང་བསྐྱར་ཚོད་ལྟ་བྱེད་རོགས། Account locked permanently. དུས་གཏན་དུ་ཟྭ་བརྒྱབ་པའི་རྩིས་ཐོ། Password cannot be empty གསང་གྲངས་སྟོང་པ་ཡིན་མི་སྲིད། Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities %1ལ་ཞིབ་བཤེར་བྱེད་མ་ཐུབ་ན། ཁྱེད་ཚོར་ད་དུང་%2ལ་ཞིབ་བཤེར་བྱེད་པའི་གོ་སྐབས་ཡོད། An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: གསང་གྲངས་ནི། Please enter your password or enroll your fingerprint གསང་གྲངས་ནང་འཇུག་གམ་ཡང་ན།འཛུབ་རིས་ཕབ་འཇུག་གནང་རོགས། wechat འཕྲིན་ཕྲན། Use the bound %1 scanning code to authorization བཀྱིགས་བཀོད་བྱས་པའི་བརྒྱ་ཆ་1བཀོལ་ནས་དབང་ཆ་བསྐུར་བ། Abnormal network རྒྱུན་ལྡན་མིན་པའི་དྲ་ This operation requires the administrator's authorization. Please enter your password to allow this operation. ཐེངས་འདིའི་བཀོལ་སྤྱོད་ལ་དོ་དམ་པས་དབང་སྐུར་ན་གཞི་ནས་མུ་མཐུད་ལག་སྟར་བྱེད་ཐུབ། གསང་གྲངས་ནང་འཇུག་བྱས་ན་ཐེངས་འདིའི་བཀོལ་སྤྱོད་བྱས་ཆོག _Password: གསང་གྲངས།: _Password: གསང་གྲངས།: Authentication failed, please try again. ར་སྤྲོད་མ་ཐུབ། ཡང་བསྐྱར་ཚོད་ལེན་བྱེད་རོགས།。 days left ཉིན་དུ་མའི་རྗེས་སུ་ཁ་ཕྱེ། Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock %1ལ་ཞིབ་བཤེར་བྱེད་མ་ཐུབ་ན། གསང་གྲངས་ནང་འཇུག་བྱས་ནས་ཟྭ་རྒྱག་རོགས། Unable to verify %1, please enter password to unlock %1ལ་ཞིབ་བཤེར་བྱེད་ཐབས་བྲལ་བ་དང་། གསང་གྲངས་ནང་འཇུག་བྱས་ནས་ཟྭ་རྒྱག་རོགས། NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. བ་རིམ་གཅིག་གིས་ཁྱད་དབང་དགོས་པའི་འགུལ་སྟངས་ཚོད་ལེན་བྱེད་སྐབས། དབང་སྐུར་རྗེས་འགུལ་སྟངས་དེ་ལག་སྟར་བྱེད་དགོས་ Input Password གསང་གྲངས་ནང་འཇུག Insert the ukey into the USB port བདེ་འཇགས་ཀྱི་གསང་བའི་ལྡེ་མིག་དེ་USBཡི་སྣེ་འདྲེན་དུ་འཇུག་རོགས། Enter the ukey password གསང་བའི་ཨང་གྲངས་ནང་འཇུག་བྱེད་པ། Close རྒྱག་པ། Enter the two-factor authentication (2FA) OTP token for the administrator "%1" དོ་དམ་པའི"བརྒྱ་ཆ་1"ཡི་རྒྱུ་རྐྱེན་གཉིས་ཀྱི་ཐོབ་ཐང་ཚོད་ལྟས་ར་སྤྲོད། (2FAA)བཀའ་རྒྱ་བྱང་བུ། Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" སྤྱོད་མཁན་གྱི་"བརྒྱ་ཆ་1"ཡི་རྒྱུ་རྐྱེན་གཉིས་ཀྱི་ཐོབ་ཐང་ཚོད་ལྟས་ར་སྤྲོད།(2FAA)འགུལ་རྣམ་བཀའ་རྒྱ་བྱང་བུ། Enter the two-factor authentication (2FA) security key for the administrator "%1" དོ་དམ་པ་"1"ཡི་རྒྱུ་རྐྱེན་གཉིས་ཀྱི་ཐོབ་ཐང་ཚོད་ལྟས་ར་སྤྲོད།(2FA)བདེ་འཇགས་ཀྱི་ལྡེ་མིག Enter the two-factor authentication (2FA) security key for the user "%1" སྤྱོད་མཁན་གྱི་"བརྒྱ་ཆ་1"ཡི་རྒྱུ་རྐྱེན་གཉིས་ཀྱི་ཐོབ་ཐང་ཚོད་ལྟས་ར་སྤྲོད།(2FA) Facial recognition to authorization གདོང་རིས་ངོས་བཟུང་ནས་དབང་སྐུར། Fingerprint recognition to authorization འཛུབ་རིས་ངོས་བཟུང་ནས་དབང་སྐུར། Voiceprint recognition to authorization སྒྲ་རིས་ངོས་བཟུང་ནས་དབང་སྐུར། Finger veins recognition to authorization འཛུབ་མོའི་སྡོད་རྩ་ངོས་བཟུང་ནས་དབང་སྐུར། Iris recognition to authorization འཇའ་སྐྱི་ངོས་བཟུང་ནས་དབང་སྐུར། Acquisition failure ཕམ་ཉེས་བྱུང་བ་རེད། hours left ཆུ་ཚོད་གཅིག་གི་རྗེས་ནས་ཁ་ཕྱེ། minutes left སྐར་མ་ཁ་ཤས་རྗེས་ཁ་ཕྱེ། seconds left སྐར་ཆ་ཁ་ཤས་རྗེས་ཁ་ཕྱེ། Input your password to authentication གསང་གྲངས་ནང་འཇུག་བྱས་ནས་དབང་སྐུར། Verify face recognition or enter password to unlock དཔང་མིའི་གདོང་ལ་ཞིབ་བཤེར་བྱེད་པའམ་ཡང་ན་གསང་གྲངས་བསྣན་ནས་ཟྭ་འབྱེད་པ། Press fingerprint or enter password to unlock མཛུབ་རིས་མནན་པའམ་ཡང་ན་གསང་གྲངས་བསྣན་ནས་ཟྭ་འབྱེད་པ། Verify voiceprint or enter password to unlock སྒྲ་རིས་ར་སྤྲོད་བྱེད་པའམ་ཡང་ན་གསང་གྲངས་བསྣན་ནས་ཟྭ་འབྱེད་པ། Verify finger vein or enter password to unlock ཚོད་ལྟས་ར་སྤྲོད་བྱེད་པ་ནི་སྡོད་རྩ་དང་གསང་གྲངས་བསྣན་ནས་ཟྭ་འབྱེད་པ་དེ་ཡིན། Verify iris or enter password to unlock འཇའ་སྐྱི་ར་སྤྲོད་བྱེད་པའམ་ཡང་ན་གསང་གྲངས་བསྣན་ནས་ཟྭ་འབྱེད་པ། Use the bound wechat scanning code or enter the password to unlock སྦྲེལ་ཡོད་པའི་སྐད་འཕྲིན་གྱི་ཨང་གྲངས་སམ་གསང་གྲངས་བསྣན་ནས་ཟྭ་འབྱེད་དགོས། Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, རྩིས་ཐོ་ཁ་རྒྱབ་ཟིན། Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. མཁོ་མཁན་སྣེ་གཞན་ཞིག་ར་སྤྲོད་བཞིན་པའི་སྒང་རེད། ཡད་ཙམ་ནས་ཚོད་ལེན་བྱེད་རོགས། Authentication failure, please try again. ར་སྤྲོད་མ་ཐུབ། ཡང་བསྐྱར་ཚོད་ལེན་བྱེད་རོགས།。 Password input error! གསང་གྲངས་ནོར་འདུག Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/vi.ts0000664000175000017500000005437115167732644020271 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication Ủy quyền LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication 授权 Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form More 更多 Restart 重新开始 Password 密码 Biometric Sinh trắc học use password Sử dụng mật khẩu để xác thực DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel Hủy Authenticate Ủy quyền Use password Sử dụng mật khẩu Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. Vui lòng thử lại sau %1 phút. Please try again in %1 seconds. Vui lòng thử lại sau%1 giây. Account locked permanently. Tài khoản bị khóa vĩnh viễn. Password cannot be empty Mật khẩu không được trống Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities Không xác minh được %1, bạn vẫn có %2 cơ hội xác minh An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: Mật khẩu: Please enter your password or enroll your fingerprint Vui lòng nhập mật khẩu hoặc dấu vân tay của bạn wechat Trò chuyện Use the bound %1 scanning code to authorization Sử dụng mã quét %1 ràng buộc để ủy quyền Abnormal network Lỗi mạng This operation requires the administrator's authorization. Please enter your password to allow this operation. Thao tác này cần có sự ủy quyền từ của quản trị viên mới có thể được thực hiện tiếp tục. Vui lòng nhập mật khẩu để cho phép thao tác lần này. _Password: Mật khẩu: _Password: _Mật khẩu: Authentication failed, please try again. Xác thực không thành công, vui lòng thử lại. days left Số ngày còn lại Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock Không xác minh được %1, vui lòng nhập mật khẩu để mở khóa Unable to verify %1, please enter password to unlock Không thể xác thực %1,vui lòng nhập mật khẩu để mở khóa NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. Một chương trình đang cố gắng thực hiện một thao tác đòi hỏi đặc quyền, yêu cầu ủy quyền để thực hiện hành động này. Input Password Nhập mật khẩu Insert the ukey into the USB port Cắm ukey vào cổng USB Enter the ukey password Nhập mật khẩu UKey Close Thoát Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Nhập mã thông báo OTP xác thực hai yếu tố (2FA) cho quản trị viên "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Nhập mã thông báo động OTP xác thực hai yếu tố (2FA) cho người dùng "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Nhập khóa bảo mật xác thực hai yếu tố (2FA) cho quản trị viên "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Nhập khóa bảo mật xác thực hai yếu tố (2FA) cho người dùng "%1" Facial recognition to authorization Nhận dạng khuôn mặt để ủy quyền Fingerprint recognition to authorization Nhận dạng vân tay để ủy quyền Voiceprint recognition to authorization Nhận dạng dấu vân giọng để ủy quyền Finger veins recognition to authorization Nhận dạng tĩnh mạch ngón tay để ủy quyền Iris recognition to authorization Nhận dạng mống mắt để ủy quyền Use the bound wechat scanning code to authorization 微信扫码以授权 Acquisition failure Lỗi khi tải hours left Số giờ còn lại minutes left Mở khóa sau phút seconds left Mở khóa sau giây Input your password to authentication Nhập mật khẩu để ủy quyền Verify face recognition or enter password to unlock 验证人脸识别或输入密码解锁 Press fingerprint or enter password to unlock 按压指纹或输入密码解锁 Verify voiceprint or enter password to unlock 验证声纹或输入密码解锁 Verify finger vein or enter password to unlock 验证指静脉或输入密码解锁 Verify iris or enter password to unlock 验证虹膜或输入密码解锁 Use the bound wechat scanning code or enter the password to unlock 使用绑定的微信扫码或输入密码解锁 Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, Tài khoản đã bị khóa, Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. Một máy khách khác đang xác thực, vui lòng thử lại sau. Authentication failure, please try again. Xác thực thất bại, vui lòng thử lại. Password input error! Lỗi nhập mật khẩu! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/mn.ts0000664000175000017500000006532015167732644020261 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication ᠡᠷᠬᠡ ᠣᠯᠭᠣᠬᠤ LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication ᠡᠷᠬᠡ ᠤᠯᠭᠤᠬᠤ Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form ᠬᠡᠯᠪᠡᠷᠢ More 更多 Restart 重新开始 Password 密码 Biometric ᠪᠢᠤᠯᠤᠬᠢ ᠵᠢᠨ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠳᠦᠬᠦᠬᠡᠷᠦᠮᠵᠢ use password ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠬᠡᠷᠡᠭᠯᠡᠵᠤ ᠪᠠᠳᠤᠯᠠᠭᠠᠵᠢᠭᠤᠯᠬᠤ DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel ᠦᠬᠡᠢᠰᠬᠡᠬᠦ Authenticate ᠡᠷᠬᠡ ᠤᠯᠭᠤᠬᠤ Use password ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠬᠡᠷᠡᠭᠯᠡᠵᠤ ᠪᠠᠳᠤᠯᠠᠭᠠᠵᠢᠭᠤᠯᠬᠤ Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. %1 ᠮᠢᠨᠦ᠋ᠲ᠎ᠦᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠳᠠᠬᠢᠵᠤ ᠳᠤᠷᠱᠢᠭᠠᠷᠠᠢ᠃ Please try again in %1 seconds. %1 ᠮᠢᠨᠦ᠋ᠲ᠎ᠦᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠳᠠᠬᠢᠵᠤ ᠳᠤᠷᠱᠢᠭᠠᠷᠠᠢ᠃ Account locked permanently. ᠳᠠᠩᠰᠠ ᠨᠢᠭᠡᠨᠳᠡ ᠦᠨᠢᠳᠡ ᠤᠨᠢᠰᠤᠯᠠᠭᠳᠠᠪᠠ᠃ Password cannot be empty ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠬᠤᠭᠤᠰᠤᠨ ᠪᠠᠢᠵᠤ ᠪᠤᠯᠬᠤ ᠦᠬᠡᠢ Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities %1᠎ᠶᠢᠨ/᠎ᠦᠨ ᠰᠢᠯᠭᠠᠨ ᠪᠠᠢᠴᠠᠭᠠᠯᠳᠠ ᠢᠯᠠᠭᠳᠠᠪᠠ ᠂ ᠲᠠ ᠪᠠᠰᠠ%2 ᠤᠳᠠᠭᠠᠨ᠎ᠤ ᠳᠤᠷᠱᠢᠬᠤ ᠵᠠᠪᠱᠢᠶᠠᠨ ᠲᠠᠢ An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋᠄ Please enter your password or enroll your fingerprint ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠪᠤᠶᠤ ᠬᠤᠷᠤᠭᠤᠨ ᠤ᠋ ᠤᠷᠤᠮ ᠵᠢᠨᠨ ᠤᠷᠤᠭᠤᠯᠤᠭᠠᠷᠠᠢ wechat ᠸᠢᠴᠠᠲ Use the bound %1 scanning code to authorization %1 ᠺᠣᠳ᠋ ᠰᠢᠷᠪᠢᠵᠤ ᠡᠷᠬᠡ ᠣᠯᠭᠣᠬᠤ Abnormal network ᠲᠤᠷ ᠰᠦᠯᠵᠢᠶ᠎ᠡ ᠬᠡᠪ ᠤ᠋ᠨ ᠪᠤᠰᠤ This operation requires the administrator's authorization. Please enter your password to allow this operation. ᠳᠤᠰ ᠤᠳᠠᠭᠠᠨ ᠤ᠋ ᠠᠵᠢᠯᠯᠠᠬᠤᠢ ᠵᠢᠨ ᠬᠠᠮᠢᠶᠠᠷᠤᠭᠴᠢ ᠵᠢᠨ ᠡᠷᠬᠡ ᠤᠯᠭᠤᠯᠳᠠ ᠪᠡᠷ ᠰᠠᠶᠢ ᠦᠷᠬᠦᠯᠵᠢᠯᠡᠨ ᠬᠡᠷᠡᠭᠵᠢᠬᠦᠯᠦᠨ᠎ᠡ᠂ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠵᠢᠨᠨ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠳᠤᠰ ᠠᠵᠢᠯᠯᠠᠬᠤᠢ ᠵᠢ ᠵᠦᠪᠰᠢᠶᠡᠷᠡᠭᠡᠷᠡᠢ᠃ _Password: ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋: _Password: ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋(_P): Authentication failed, please try again. ᠬᠡᠷᠡᠴᠢᠯᠡᠵᠤ ᠴᠢᠳᠠᠭᠰᠠᠨ ᠦᠬᠡᠢ᠂ ᠳᠠᠬᠢᠵᠤ ᠳᠤᠷᠰᠢᠭᠠᠷᠠᠢ᠃ days left ᠡᠳᠦᠷ ᠤ᠋ᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠤᠨᠢᠰᠤ ᠳᠠᠢᠯᠤᠨ᠎ᠠ Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock %1᠎ᠶᠢ/᠎ᠢ ᠪᠠᠳᠤᠯᠭᠠᠵᠢᠭᠤᠯᠬᠤ ᠠᠷᠭ᠎ᠠ ᠦᠬᠡᠢ ᠂ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ Unable to verify %1, please enter password to unlock %1᠎ᠶᠢ/᠎ᠢ ᠪᠠᠳᠤᠯᠭᠠᠵᠢᠭᠤᠯᠬᠤ ᠠᠷᠭ᠎ᠠ ᠦᠬᠡᠢ ᠂ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. ᠨᠢᠭᠡ ᠫᠡᠷᠦᠭᠷᠡᠮ ᠶᠠᠭ ᠨᠢᠭᠡ ᠤᠨᠠᠴᠠ ᠡᠷᠬᠡ ᠬᠡᠷᠡᠭᠰᠡᠬᠦ ᠬᠦᠳᠡᠯᠬᠡᠬᠡᠨ ᠢ᠋ ᠬᠡᠷᠡᠭᠵᠢᠬᠦᠯᠬᠦ ᠪᠡᠷ ᠳᠤᠷᠰᠢᠵᠤ ᠪᠠᠢᠨ᠎ᠠ᠂ ᠳᠤᠰ ᠬᠦᠳᠡᠯᠬᠡᠬᠡᠨ ᠢ᠋ ᠬᠦᠢᠴᠡᠳᠬᠡᠬᠦ ᠡᠷᠬᠡ ᠤᠯᠭᠤᠬᠤ ᠵᠢ ᠱᠠᠭᠠᠷᠳᠠᠵᠤ ᠪᠠᠢᠨ᠎ᠠ᠃ Input Password ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠣᠷᠣᠭᠤᠯᠬᠤ Insert the ukey into the USB port ᠠᠮᠤᠷ ᠳᠦᠪᠰᠢᠨ ᠤ᠋ ᠨᠢᠭᠤᠴᠠ ᠳᠦᠯᠬᠢᠬᠦᠷ ᠢ᠋ USB ᠦᠵᠦᠭᠦᠷ ᠲᠤ᠌ ᠬᠠᠪᠴᠢᠭᠤᠯᠤᠭᠠᠷᠠᠢ Enter the ukey password ᠠᠮᠤᠷ ᠳᠦᠪᠰᠢᠨ ᠤ᠋ ᠨᠢᠭᠤᠴᠠ ᠳᠦᠯᠬᠢᠬᠦᠷ ᠤ᠋ᠨ ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠢ᠋ ᠣᠷᠣᠭᠤᠯᠬᠤ Close ᠬᠠᠭᠠᠬᠤ Enter the two-factor authentication (2FA) OTP token for the administrator "%1" "%1" ᠬᠠᠮᠢᠶᠠᠷᠤᠭᠴᠢ ᠵᠢᠨ ᠬᠣᠣᠰ ᠹᠠᠺᠲ᠋ᠣᠷ᠎ᠤ᠋ᠨ ᠭᠡᠷᠡᠴᠢᠯᠡᠯ OTP ᠬᠥᠳᠡᠯᠦᠩᠭᠦᠢ ᠠᠮᠠᠨ ᠳᠣᠬᠢᠶ᠎ᠠ ᠵᠢ ᠣᠷᠣᠭᠤᠯᠬᠤ Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" "%1" ᠬᠠᠮᠢᠶᠠᠷᠤᠭᠴᠢ ᠵᠢᠨ ᠬᠣᠣᠰ ᠹᠠᠺᠲ᠋ᠣᠷ᠎ᠤ᠋ᠨ ᠭᠡᠷᠡᠴᠢᠯᠡᠯ OTP ᠬᠥᠳᠡᠯᠦᠩᠭᠦᠢ ᠠᠮᠠᠨ ᠳᠣᠬᠢᠶ᠎ᠠ ᠵᠢ ᠣᠷᠣᠭᠤᠯᠬᠤ Enter the two-factor authentication (2FA) security key for the administrator "%1" "%1" ᠬᠠᠮᠢᠶᠠᠷᠤᠭᠴᠢ ᠵᠢᠨ ᠬᠣᠣᠰ ᠹᠠᠺᠲ᠋ᠣᠷ᠎ᠤ᠋ᠨ ᠭᠡᠷᠡᠴᠢᠯᠡᠯ ᠤ᠋ᠨ ᠠᠮᠤᠷ ᠳᠦᠪᠰᠢᠨ ᠤ᠋ ᠨᠢᠭᠤᠴᠠ ᠳᠦᠯᠬᠢᠬᠦᠷ ᠢ᠋ ᠣᠷᠣᠭᠤᠯᠬᠤ Enter the two-factor authentication (2FA) security key for the user "%1" "%1" ᠬᠠᠮᠢᠶᠠᠷᠤᠭᠴᠢ ᠵᠢᠨ ᠬᠣᠣᠰ ᠹᠠᠺᠲ᠋ᠣᠷ᠎ᠤ᠋ᠨ ᠭᠡᠷᠡᠴᠢᠯᠡᠯ ᠤ᠋ᠨ ᠠᠮᠤᠷ ᠳᠦᠪᠰᠢᠨ ᠤ᠋ ᠨᠢᠭᠤᠴᠠ ᠳᠦᠯᠬᠢᠬᠦᠷ ᠢ᠋ ᠣᠷᠣᠭᠤᠯᠬᠤ Facial recognition to authorization ᠴᠢᠷᠠᠢ ᠪᠡᠷ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠡᠷᠬᠡ ᠣᠯᠭᠣᠬᠤ Fingerprint recognition to authorization ᠬᠤᠷᠤᠭᠤᠨ ᠣᠷᠣᠮ ᠵᠢᠡᠷ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠡᠷᠬᠡ ᠣᠯᠭᠣᠬᠤ Voiceprint recognition to authorization ᠳᠠᠭᠤᠨ ᠣᠷᠣᠮ ᠵᠢᠡᠷ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠡᠷᠬᠡ ᠣᠯᠭᠣᠬᠤ Finger veins recognition to authorization ᠨᠠᠮᠵᠢᠭᠤᠨ ᠰᠤᠳᠠᠰᠤ ᠪᠡᠷ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠡᠷᠬᠡ ᠣᠯᠭᠣᠬᠤ Iris recognition to authorization ᠴᠡᠴᠡᠬᠡᠢ ᠪᠡᠷ ᠢᠯᠭᠠᠨ ᠳᠠᠨᠢᠬᠤ ᠡᠷᠬᠡ ᠣᠯᠭᠣᠬᠤ Acquisition failure ᠣᠯᠵᠤ ᠴᠢᠳᠠᠭᠰᠠᠨ ᠥᠬᠡᠢ hours left ᠨᠢᠭᠡ ᠴᠠᠭ ᠤ᠋ᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠤᠨᠢᠰᠤ ᠳᠠᠢᠯᠤᠨ᠎ᠠ minutes left ᠮᠢᠨᠦ᠋ᠲ ᠤ᠋ᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠤᠨᠢᠰᠤ ᠳᠠᠢᠯᠤᠨ᠎ᠠ seconds left ᠰᠸᠺᠦᠨ᠋ᠲ ᠤ᠋ᠨ ᠳᠠᠷᠠᠭ᠎ᠠ ᠤᠨᠢᠰᠤ ᠳᠠᠢᠯᠤᠨ᠎ᠠ Input your password to authentication ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠣᠷᠣᠭᠤᠯᠵᠤ ᠡᠷᠬᠡ ᠣᠯᠭᠣᠨ᠎ᠠ Verify face recognition or enter password to unlock ᠨᠢᠭᠤᠷ ᠱᠢᠷᠪᠢᠵᠤ ᠪᠠᠳᠤᠯᠭᠠᠵᠢᠭᠤᠯᠬᠤ ᠪᠤᠶᠤ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ Press fingerprint or enter password to unlock ᠬᠤᠷᠤᠭᠤᠨ᠎ᠤ ᠤᠷᠤᠮ ᠳᠠᠷᠤᠬᠤ ᠪᠤᠶᠤ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ Verify voiceprint or enter password to unlock ᠳᠠᠭᠤ᠎ᠪᠠᠷ ᠰᠢᠯᠭᠠᠨ ᠪᠠᠳᠤᠯᠠᠬᠤ ᠪᠤᠶᠤ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ Verify finger vein or enter password to unlock ᠬᠤᠷᠤᠭᠤᠨ᠎ᠤ ᠨᠠᠮᠵᠢᠭᠤᠨ ᠰᠤᠳᠠᠯ᠎ᠢᠶᠠᠷ ᠰᠢᠯᠭᠠᠨ ᠪᠠᠳᠤᠯᠠᠬᠤ ᠪᠤᠶᠤ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ Verify iris or enter password to unlock ᠰᠤᠯᠤᠩᠭ᠎ᠠ ᠪᠦᠷᠬᠦᠪᠴᠢ᠎ᠶᠢ ᠰᠢᠯᠭᠠᠨ ᠪᠠᠳᠤᠯᠠᠬᠤ ᠪᠤᠶᠤ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ Use the bound wechat scanning code or enter the password to unlock ᠤᠶᠠᠭᠰᠠᠨ ᠸᠢᠴᠠᠲ᠎ᠢᠶᠠᠷ ᠺᠤᠳ᠋ ᠱᠢᠷᠪᠢᠬᠦ᠌ ᠪᠤᠶᠤ ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠤᠷᠤᠭᠤᠯᠵᠤ ᠤᠨᠢᠰᠤ᠎ᠶᠢ ᠳᠠᠢᠯᠤᠭᠠᠷᠠᠢ Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, ᠳᠠᠨᠭᠰᠠ ᠵᠢ ᠨᠢᠬᠡᠨᠳᠡ ᠤᠨᠢᠰᠤᠯᠠᠪᠠ Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. ᠦᠬᠡᠷ᠎ᠡ ᠨᠢᠭᠡ ᠬᠡᠷᠡᠭᠯᠡᠭᠴᠢ ᠵᠢᠨ ᠦᠵᠦᠬᠦᠷᠯᠢᠭ ᠢ᠋ ᠶᠠᠭ ᠨᠤᠳᠠᠯᠠᠵᠤ ᠪᠠᠢᠨ᠎ᠠ᠂ ᠤᠳᠠᠰᠬᠢᠭᠠᠳ ᠳᠠᠬᠢᠨ ᠳᠤᠷᠰᠢᠭᠠᠷᠠᠢ᠃ Authentication failure, please try again. ᠬᠡᠷᠡᠴᠢᠯᠡᠵᠤ ᠴᠢᠳᠠᠭᠰᠠᠨ ᠦᠬᠡᠢ᠂ ᠳᠠᠬᠢᠵᠤ ᠳᠤᠷᠰᠢᠭᠠᠷᠠᠢ᠃ Password input error! ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ ᠢ᠋ ᠪᠤᠷᠤᠭᠤ ᠤᠷᠤᠭᠤᠯᠪᠠ! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/fr.ts0000664000175000017500000005343115167732644020256 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication Authentification LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication Authentification Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form More 更多 Restart 重新开始 Password 密码 Biometric Biométrique use password Utiliser le mot de passe DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel Annuler Authenticate Authentifier Use password Utiliser le mot de passe Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. Veuillez réessayer dans %1 minutes. Please try again in %1 seconds. Veuillez réessayer dans %1 secondes. Account locked permanently. Compte verrouillé définitivement. Password cannot be empty Le mot de passe ne peut pas être vide Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities Échec de la vérification %1, vous avez encore %2 possibilités de vérification An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: Mot de passe: Please enter your password or enroll your fingerprint Veuillez saisir votre mot de passe ou enregistrer votre empreinte digitale wechat Use the bound %1 scanning code to authorization Abnormal network Réseau anormal This operation requires the administrator's authorization. Please enter your password to allow this operation. Cette opération nécessite l’autorisation de l’administrateur. Veuillez saisir votre mot de passe pour autoriser cette opération. _Password: _Mot de passe: _Password: _Mot de passe: Authentication failed, please try again. L’authentification a échoué, veuillez réessayer. days left jours restants Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock Impossible de vérifier %1, veuillez entrer le mot de passe pour déverrouiller Unable to verify %1, please enter password to unlock Impossible de vérifier %1, veuillez entrer le mot de passe pour déverrouiller NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. Un programme tente d’effectuer une action qui nécessite des privilèges. Il nécessite une autorisation pour effectuer l’action. Input Password Mot de passe d’entrée Insert the ukey into the USB port Enter the ukey password Close Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Acquisition failure hours left Heures restantes minutes left minutes restantes seconds left secondes restantes Input your password to authentication Verify face recognition or enter password to unlock Vérifier la reconnaissance faciale ou saisir le mot de passe pour déverrouiller Press fingerprint or enter password to unlock Appuyez sur l’empreinte digitale ou entrez le mot de passe pour déverrouiller Verify voiceprint or enter password to unlock Vérifier l’empreinte vocale ou saisir le mot de passe pour déverrouiller Verify finger vein or enter password to unlock Vérifiez la veine du doigt ou entrez le mot de passe pour déverrouiller Verify iris or enter password to unlock Vérifiez l’iris ou entrez le mot de passe pour déverrouiller Use the bound wechat scanning code or enter the password to unlock Utilisez le code d’analyse wechat lié ou entrez le mot de passe pour déverrouiller Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, Compte verrouillé, Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. Un autre client est déjà en train de s’authentifier, veuillez réessayer plus tard. Authentication failure, please try again. Échec de l’authentification, veuillez réessayer. Password input error! Erreur de saisie du mot de passe ! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/es.ts0000664000175000017500000005313415167732644020256 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication Autenticación LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication Autenticación Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form Forma More 更多 Restart 重新开始 Password 密码 Biometric Biométrico use password Usar contraseña DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel Cancelar Authenticate Autentificar Use password Usar contraseña Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. Inténtelo de nuevo en %1 minutos. Please try again in %1 seconds. Inténtelo de nuevo en %1 segundos. Account locked permanently. Cuenta bloqueada permanentemente. Password cannot be empty La contraseña no puede estar vacía Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities No se pudo verificar %1, todavía tiene %2 oportunidades de verificación An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: Contraseña: Please enter your password or enroll your fingerprint Ingrese su contraseña o registre su huella dactilar wechat Use the bound %1 scanning code to authorization Abnormal network Red anormal This operation requires the administrator's authorization. Please enter your password to allow this operation. Esta operación requiere la autorización del administrador. Introduzca su contraseña para permitir esta operación. _Password: _Contraseña: _Password: _Contraseña: Authentication failed, please try again. Error de autenticación, inténtelo de nuevo. days left Días restantes Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock No se pudo verificar %1, ingrese la contraseña para desbloquear Unable to verify %1, please enter password to unlock No se puede verificar %1, ingrese la contraseña para desbloquear NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. Un programa está intentando realizar una acción que requiere privilegios. Requiere autorización para realizar la acción. Input Password Contraseña de entrada Insert the ukey into the USB port Enter the ukey password Close Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization Fingerprint recognition to authorization Voiceprint recognition to authorization Finger veins recognition to authorization Iris recognition to authorization Acquisition failure hours left horas restantes minutes left Quedan minutos seconds left segundos restantes Input your password to authentication Verify face recognition or enter password to unlock Verifique el reconocimiento facial o ingrese la contraseña para desbloquear Press fingerprint or enter password to unlock Presione la huella dactilar o ingrese la contraseña para desbloquear Verify voiceprint or enter password to unlock Verifica la huella de voz o ingresa la contraseña para desbloquear Verify finger vein or enter password to unlock Verifique la vena del dedo o ingrese la contraseña para desbloquear Verify iris or enter password to unlock Verifique el iris o ingrese la contraseña para desbloquear Use the bound wechat scanning code or enter the password to unlock Use el código de escaneo de wechat vinculado o ingrese la contraseña para desbloquear Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, Cuenta bloqueada, Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. Otro cliente ya se está autenticando, inténtelo de nuevo más tarde. Authentication failure, please try again. Error de autenticación, inténtelo de nuevo. Password input error! ¡Error de entrada de contraseña! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/i18n_ts/zh_HK.ts0000664000175000017500000005241615167732644020654 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication 授權 LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication 授權 Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form More 更多 Restart 重新开始 Password 密码 Biometric 使用生物識別 use password 使用密碼驗證 DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel 取消 Authenticate 授權 Use password 使用密碼驗證 Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. 請%1分鐘后再試 Please try again in %1 seconds. 請%1秒後再試 Account locked permanently. 帳號已被永久鎖定 Password cannot be empty 密碼不能為空 Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities 驗證%1失敗,您還有%2次嘗試機會 An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: 密碼: Please enter your password or enroll your fingerprint 請輸入密碼或者錄入指紋 wechat 微信 Use the bound %1 scanning code to authorization %1掃碼以授權 Abnormal network 網路異常 This operation requires the administrator's authorization. Please enter your password to allow this operation. 本次操作需要通過管理員的授權才能繼續執行,請輸入密碼以允許本次操作。 _Password: 密碼: _Password: 密碼: Authentication failed, please try again. 認證失敗,請重試。 days left 天后解鎖 Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock 驗證%1失敗,請輸入密碼解鎖 Unable to verify %1, please enter password to unlock 無法驗證%1,請輸入密碼解鎖 NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. 一個程式正試圖執行一個需要特權的動作,要求授權以執行該動作。 Input Password 輸入密碼 Insert the ukey into the USB port 請將安全金鑰插入USB埠 Enter the ukey password 輸入安全金鑰密碼 Close 關閉 Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization 識別人臉以授權 Fingerprint recognition to authorization 識別指紋以授權 Voiceprint recognition to authorization 識別聲紋以授權 Finger veins recognition to authorization 識別指靜脈以授權 Iris recognition to authorization 識別虹膜以授權 Use the bound wechat scanning code to authorization 微信掃碼以授權 Acquisition failure 獲取失敗 hours left 小時後解鎖 minutes left 分鐘後解鎖 seconds left 秒後解鎖 Input your password to authentication 輸入密碼以認證 Verify face recognition or enter password to unlock 驗證人臉識別或輸入密碼解鎖 Press fingerprint or enter password to unlock 按壓指紋或輸入密碼解鎖 Verify voiceprint or enter password to unlock 驗證聲紋或輸入密碼解鎖 Verify finger vein or enter password to unlock 驗證指靜脈或輸入密碼解鎖 Verify iris or enter password to unlock 驗證虹膜或輸入密碼解鎖 Use the bound wechat scanning code or enter the password to unlock 使用綁定的微信掃碼或輸入密碼解鎖 Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, 帳戶已鎖定, Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. 有另外一個用戶端正在認證,請稍後重試。 Authentication failure, please try again. 認證失敗,請重試。 Password input error! 密碼輸入錯誤! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/polkit-agent/data/0000775000175000017500000000000015167732644016715 5ustar fengfengukui-biometric-auth/polkit-agent/data/polkit-ukui-authentication-agent-1.desktop.in0000664000175000017500000001033315167732644027441 0ustar fengfeng[Desktop Entry] Name=PolicyKit Authentication Agent Name[ca]=Agent d'autenticació del PolicyKit Name[ca@valencia]=Agent d'autenticació del PolicyKit Name[cs]=Ověřovací agent PolicyKitu Name[da]=PolicyKit autentificeringsagent Name[de]=PolicyKit-Authentifizierungs-Agent Name[el]=Πράκτορας ταυτοποίησης PolicyKit Name[en_GB]=PolicyKit Authentication Agent Name[es]=Agente de autenticación de PolicyKit Name[et]=PolicyKiti autentimisagent Name[eu]=PolicyKit autentifikazio agentea Name[fi]=PolicyKit-tunnistautumisagentti Name[fr]=Agent d'authentification de « PolicyKit » Name[gl]=Axente de autenticación de PolicyKit Name[hu]=PolicyKit hitelesítési ügynök Name[id]=PolicyKit Authentication Agent Name[it]=Agente di autenticazione di PolicyKit Name[ko]=PolicyKit 인증 에이전트 Name[nl]=Authenticatieagent van PolicyKit Name[nn]=PolicyKit-autentiseringsagent Name[pa]=ਪਾਲਸੀਕਿਟ ਪਰਮਾਣਕਿਤਾ ਏਜੰਟ Name[pl]=Usługa uwierzytelnienia PolicyKit Name[pt]=Agente de Autenticação do PolicyKit Name[pt_BR]=Agente de Autenticação do PolicyKit Name[ru]=Агент аутентификации PolicyKit Name[sk]=Overovací dialóg PolicyKit Name[sl]=Overitveni posrednik PolicyKit Name[sr]=Полисикитов агент за аутентификовање Name[sr@ijekavian]=Полисикитов агент за аутентификовање Name[sr@ijekavianlatin]=PolicyKitov agent za autentifikovanje Name[sr@latin]=PolicyKitov agent za autentifikovanje Name[sv]=Policykit behörighetsmodul Name[tr]=PolicyKit Kimlik Doğrulama Aracı Name[uk]=Агент розпізнавання PolicyKit Name[x-test]=xxPolicyKit Authentication Agentxx Name[zh_CN]=PolicyKit 认证代理 Name[zh_TW]=PolicyKit 認證代理程式 Name[ug_CN]=PolicyKit ئىسپات ۋاكالەتچىلىكى Name[kk_KZ]=PolicyKit دالەل ۆاكىلى Name[ky_KG]=PolicyKit ىسپات ۋاكالەتچىلىكى Comment=PolicyKit Authentication Agent Comment[ca]=Agent d'autenticació del PolicyKit Comment[ca@valencia]=Agent d'autenticació del PolicyKit Comment[cs]=Ověřovací agent PolicyKitu Comment[da]=PolicyKit autentificeringsagent Comment[de]=PolicyKit-Authentifizierungs-Agent Comment[el]=Πράκτορας ταυτοποίησης PolicyKit Comment[en_GB]=PolicyKit Authentication Agent Comment[es]=Agente de autenticación de PolicyKit Comment[et]=PolicyKiti autentimisagent Comment[eu]=PolicyKit autentifikazio agentea Comment[fi]=PolicyKit-tunnistautumisagentti Comment[fr]=Agent d'authentification de « PolicyKit » Comment[gl]=Axente de autenticación de PolicyKit Comment[hu]=PolicyKit hitelesítési ügynök Comment[id]=Agen Kewenangan PolicyKit Comment[it]=Agente di autenticazione di PolicyKit Comment[ko]=PolicyKit 인증 에이전트 Comment[nl]=Authenticatieagent van PolicyKit Comment[nn]=PolicyKit-autentiseringsagent Comment[pa]=ਪਾਲਸੀਕਿਟ ਪਰਮਾਣਕਿਤਾ ਏਜੰਟ Comment[pl]=Usługa uwierzytelnienia PolicyKit Comment[pt]=Agente de Autenticação do PolicyKit Comment[pt_BR]=Agente de Autenticação do PolicyKit Comment[ru]=Агент аутентификации PolicyKit Comment[sk]=Overovací dialóg PolicyKit Comment[sl]=Overitveni posrednik PolicyKit Comment[sr]=Полисикитов агент за аутентификовање Comment[sr@ijekavian]=Полисикитов агент за аутентификовање Comment[sr@ijekavianlatin]=PolicyKitov agent za autentifikovanje Comment[sr@latin]=PolicyKitov agent za autentifikovanje Comment[sv]=Policykit behörighetsmodul Comment[tr]=PolicyKit Kimlik Doğrulama Aracı Comment[uk]=Агент розпізнавання PolicyKit Comment[x-test]=xxPolicyKit Authentication Agentxx Comment[zh_CN]=PolicyKit 认证代理 Comment[zh_TW]=PolicyKit 認證代理程式 Exec=${LIB_ARCH_PATH}/ukui-polkit/polkit-ukui-authentication-agent-1 Icon=ukui-polkit Terminal=false Type=Application Categories=System;Security; OnlyShowIn=UKUI;MATE X-UKUI-StartupNotify=false X-UKUI-AutoRestart=true X-UKUI-Autostart-Phase=Application NoDisplay=true X-DBUS-StartupType=Unique X-MATE-Autostart-Phase=Initialization X-MATE-StartupNotify=false X-MATE-AutoRestart=true X-KDE-Wayland-Interfaces=org_kde_plasma_window_management,org_kde_kwin_keystate ukui-biometric-auth/images/0000775000175000017500000000000015167732630014646 5ustar fengfengukui-biometric-auth/images/FingerPrint.png0000664000175000017500000004472515167732630017617 0ustar fengfengPNG  IHDRg- pHYs.#.#x?v9iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2018-06-22T10:02:14+08:00 2018-07-02T11:05:22+08:00 2018-07-02T11:05:22+08:00 image/png 3 xmp.iid:d25dd608-d1a1-4345-8aed-f31ffb97fc5f adobe:docid:photoshop:bf20e7c4-7da4-11e8-92f2-d9e6550a8a6d xmp.did:3a170e97-9755-d640-8f8f-3f9b31c0e3ae created xmp.iid:3a170e97-9755-d640-8f8f-3f9b31c0e3ae 2018-06-22T10:02:14+08:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:d25dd608-d1a1-4345-8aed-f31ffb97fc5f 2018-07-02T11:05:22+08:00 Adobe Photoshop CC 2017 (Windows) / 1 3000000/10000 3000000/10000 2 65535 160 160 4F 5 cHRMz%u0`:o_F_IDATxMv6dnm@ :i 4++(+(= T:hgVPh|^V4HJust; .7}Cހ坾wl叙uM1,uz뒱Wd f1,bY,X d:;NDH,FSwS8W"OTd/w/=*2)Wps C( ƴ! [݀0+@  9]n5r8L %v,vK XXcu_@ƛG1h[߁۱.b&k{q)/b^Em Ja^Xhe+q(,]WQ :. +K,lCyU[XRBTWJ<x<GJJC+W"u&/~%źebY,巸>A]˸VcZ\6ȧgƟ,Xe氟՚LH/y3C* !8׵;x&rdBJ+~'wț2nN=K8JE2r޷\YD:x&R=!jCy^ЍibDȗKW!.^5!sкTYV' ҥ>w, O@%̋ņ[e|'_ dk YIx&"۞!_ry`r@Jv4;x&3Q-R?`v9; o0з%))K] o3d_[8P2"rƼPӠqDww?n(DXHyLӆٯD1`=GqޯDLk# !uyqAք\.jaw<|+~|#8k3ynrNn*jJC @n3yq9hZ MWa2BS@TAwdܹG a]bJd}!U~* ԩ3`p:Ж,GP/g^L3#sL<ԭǧi݃㼙^HV Q>#vf%kS2 ]Yӵ}F0*" Z(b\Ur7 /Y%UAe06wW7WL׿୑o&|j͡6$$w h$5 0ԴYbLlt47)ļύ }wlvW~SQ3م I#zϖ1YLg0S佰P~Wp-bݚڡ~0N3Ɔq)4pu޹H+62#7dba|{v'=^Z*t-vDa Ҟ&[mɺ?,S,6`pU'f=`1zWN*SoILs6 k[݂uVpja-k)RX? Zq`]_ &YL@|9 i -* V5.xk0ސhpKNY ba M8n',ePasK;?`٥j9Fs0txNjnNB ִ !h 45κ-`C+@w!}o?W,Kk+,*[Z?%Kpe+:if@,fb3>4̺ksvU-mlb`ɖ2'gmTω}fOyaX5"\doDW8eu1$~e=.k,q hdh6iua,!?0wKZ-]W#~@#?ԍg4;S]:?HwhIG}4$K7i3&!E}6l^#rԏgbysv(C^jI8Fa YkCd9ޞ~ R?ҏsP.v9Ѐc7"we<i[~N)IN|:Upk67EWVzQVGХp@{!Tpmj)Χ>ul pׇb΋jeۀ->p|.;AWKXz"meրW2w<5]@=?MLV`n9tWfbG+I`c9k,aY^0l}K*,]3 >w*$1 mدD<2azm)s- NH6|SVib>˚"y`ZY| ;:s)Fp6n/@p~#u\|>xxI 53|ܑb7]QuDTd3L(^%o"9,Gfݍ֢,mVa0#M+켫>ƤyU|H Ͽ1B\$,InaMVFaہ/@T؎JvUZ|KWXVo:h\VٝhfR 3b6-sx/$hz0.x/ 4l{0 _O/})}@y}nKcA]HBKz0-|D^ao°o2Aȅh'!bY @d1,Vɕ6ij+~ X -F p IENDB`ukui-biometric-auth/images/ukui-loginopt-finger.svg0000664000175000017500000000457215167732630021455 0ustar fengfengukui-biometric-auth/images/Iris.png0000664000175000017500000005014315167732630016265 0ustar fengfengPNG  IHDRg- pHYs.#.#x?v9iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2018-06-22T10:02:14+08:00 2018-07-02T11:06:22+08:00 2018-07-02T11:06:22+08:00 image/png 3 xmp.iid:b78bea26-9a1f-5a40-aa24-3f1baf8c43a2 adobe:docid:photoshop:e1fcfd40-7da4-11e8-92f2-d9e6550a8a6d xmp.did:26e0b17b-aa01-6343-8adb-ad9cb203136d created xmp.iid:26e0b17b-aa01-6343-8adb-ad9cb203136d 2018-06-22T10:02:14+08:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:b78bea26-9a1f-5a40-aa24-3f1baf8c43a2 2018-07-02T11:06:22+08:00 Adobe Photoshop CC 2017 (Windows) / 1 3000000/10000 3000000/10000 2 65535 160 160 eN cHRMz%u0`:o_FIDATx]#yBkj_lW&E` Z-ugi @n,EH`\&`B#Tx= +!b+/BsF;;_JGs4?QYeYR5AeUVVY`eFI@xRҏiSt_vYgJ!T;ܞJݢ'G N<`vtg9rh4L}oI[ ¬Fl_[Fk>h  x|AU[VTmPEC򆋍BGPYLGT^/Eb:TT68ૼ\mx;ZZ ۜ =n[0"PN 5G va9S !,J|he|6J7xPeu EneTOTUFp4yjP'+ ![X/I񄊄P+ m]'4siv_) d=$ n48Eh@ivڭn8K_1x  ZUY}[B2cE@Ѱ>bU&Bnj(/;IfVR2*mP$kc}FE.zGzOohP e3N,·U=j$az0 }H:&AքJ2Q6# mJP_Bfq$W,iGW5KlNh͇@ni רv's 5X#4P*N x}qsԥh8flFЎ~0cQW߹n5H-ed7.ݹ2̼iN("*Cgz=Kv3fN[daܚt+7 il`}H)*'dRBfĊZ7]z5l`d}OHPŧ*ϥYp&Y)r ]wttlY]DĽ{ajXMNPy|(gTCj@"3 SOQRtr tgVìA:h 1>]@OHA l+%Gڨt ɏ~6C]Шt<&bU ͇ {^y@~jLh<eKݢe +4]mZᒌ59CԀq>7aYɰAU=Skx3>޻އ[S};$g˜y}":>_*pH(|k)o0(x xUF)㮜vKQ鶈3qo7 |d}kRP7|S_jT|T<z"0칾 vp Hѽeڭqv=/8qWnKDdP|A9Xmu~M;Y%නEBDϐ ڞ:dw裏b_AeAE1鮄j=rB%$*qѕqoc-3\1y'O c^/ؔ8{7)Jg_tn=.'Nמcj{L* Tks/lg2.zt |{Ss%|5ȀV<xv ODž/ŏ a-dwZey-_?7eˢDerwکx/$C#tӆ闯O}ie4BQ 'I><SF 3f-AEOUք !V uk!껴_8}}U ^x<+#@1޺` #꾽~7$\әfǁӛ6d;ZO0m&l (Y( m 黻~sϾ 1ևϞo\M?0/X_փ %od"I2l '/ÞˑOٯ?g̾쵸d*-k #{@y_+|oSۏ=s ]\xF_KWɟuqyʱG돰tXjoߔ~z ,N3P`~ nz*SiBMΦ͇Ա[d qf7 _ @, ؑLz~L@˛,Ύ2K8, o4f3/VqѶM!=dbwP `AM2 /0| }Y9pLJ0>g΢W$-ƍu ? 3~1~ұw u5NdVBx4 $0%8ޒ̏?ɤ_w 1AT2/,z%49 y]S_u5/ܿM;U>+jQ?Mg4kU"gElMXc4 tc]E<"JHjQQ@x[%MR;oMy̢닀/2! ° |T_&'Fx{O-? YiXݛ,$} G*E$&klAx{}K~4W'{DӵM{$`酋Y+׸:_jc*笭K- !gOb8p <# x7 Y[z1d,D&8Tcnyqzx@װ31@2?2HIDĊv`b57I/NZ[4?qdO]1t kE0p1]sIb8dh*eAQ郈Pcfi^Tty:&yQd5k8>aw͐ײy^BvG8di&CřR .UBR.|2=WmPiX?gSZ6'˝,R4` qZPO#,ZCC<3o}(]G.RG݌xYP粒II!]ݱtY? y(>Aރ j$/mf#Zj!>!`g&s M8CE3љ5&@en-mEBL8D6@W/5Ԡ/t6B\R6}3h=6ufPNc8ON nޫ>r_&x3Ԗ0O4NKp48fw;햙QqТk-1aS:@ 0tڭa5|#7 D9?M,v'Fĺ¨ :&Ä%%2 VsDR($żr:VS'SFi,!LqYٵREjxRЛ8h @W4I:?AnI<{' ܑa, iӜWsEf.R׾'+ ` R UxF $ຮK>~He&/|B(o">=HZVRe!5'?cpMvf7'tڭ~% '&vڭnNtNK,那(ݹ3xi3O#?Tp%$SՃUVvDyn'M'']ǂ}Q1a3Gmp8oB/ rݲب YئE0Y+Dj уKݼBU;p[ )>lX}h<^V:k4` "3,NE.֗N`+ix¼P>a)6A[AX:dT5M҄o_wi -OXae T1 U))x5wB T&V[z57ʲ%| Ǭn҅4K%3z!C*9I9:1h%AhUHi[eu'L \ݱ,LɐZ_yC!Ys&=ata wp;V `.6'^j%V[>V;Bn. SӪd_ +Cj`U+}trysQ`Qxi3f Hvct5N)4ey2IqEynmG͊  `D]*v}k.$)1@W]NUnJJݚlsXHj4}v&5+x ΕA zJ@OxV0G-=Ie+9* XYeUVVYv%~IENDB`ukui-biometric-auth/images/ukui-loginopt-smile.svg0000664000175000017500000000232415167732630021305 0ustar fengfengukui-biometric-auth/images/ukui-qrcode-null.svg0000664000175000017500000000344315167732630020573 0ustar fengfengukui-biometric-auth/images/VoicePrint.gif0000664000175000017500000003056415167732630017427 0ustar fengfengGIF89aUsD! NETSCAPE2.0! XMP DataXMP ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!  ! , &dilp,t]xzjpHl:ɨ|Zׁvz-ha4 8p-j^CWW}v"C/w5 o5X5 D352  14 +5Ҽ6̶ۻ? ?ã@ @µ{@U&*hVBS7bD6ȫ!A*Ѕ-8X@[ɗ*@J l֤UΒTMrG%yB-B(uVaͺ*vKN,Yr2H8-L6 טHu٪־$x0†!Nh1cD ,z.ccfD~tmрZH[0̧=io-m--d.@q[Nj9!ymCPA:֗K[Y ߀QU~<|wrU1z}בU{!|  }A6 "NwނMP8!u2a %aVP,ȡ؟2J!3P?HCF^"b5BQfy A2P٠IeRiX3&K9 yfbY?#[ʙdډvk9r) z&6j#QsRr꟭ΓZ+jfuZ(84ުi"+&4^*B;lٮګd ۷Ӟ. ض2L[;ۯ(&¼+0<*V" ,0LJ\2[/Ė|d.|lƹL/u2[̳, 4nv 7=O4s6/ 1P h-;-d=ji׭rS{W = t},[B<(m5}+w b03^Xy WΨóxެ]߱bSC7[CsOn?t#NN }W3{}p6X~۞F~ עәŧf|KV> ;yՏ{cWTA+NZ 0x%'@g ΁/E=BTMEݎ& B "~H [ALQU9䋇\-$'763°Tϥўɹſ⩝Ҿ^?wn>tGA"oz +f L7XPG C>4ɲˎP (R`K/ɴ$ΟWǑ7TmOkJ NW.Չ5jM5etT-;s(ڭHsr,ôlm} 'ٸk#^yI/W.ˌfu}S>l iX!Ë&ToA#TIƉ1(dI'e8Kr){>͟CE *(R .҃gӖk[ipߨmv4[ٜhSSx|[h֦3u׋~셸ףVuo]G}x")hyS4 ~J8w ^a!e!?7! ,6A`@`&fZih(p L8ފo7G<2b1c*}PWUu,-EǦ(Z("_a|b/GWy[{i[}Hh%u1=?}:bY09|wR2öƫ5ְџܪٹȿ()÷[#دቃ.TpEAPcŏ=n^ȎϤK _(eK!U$ɛ"e' P $gMCAM)ՙKcVkJ^Ta 빑X]u˓.ܦs6UlY+[v u/G.W1WLXŖ# ulc&̪Knm5ؓoamT:뾝qaւy!;l.N+ͩ>%Үx^9JGۓ?zV2oU 6'  k$ ` !! ,4A`@&dffdlB+6˯ډ 5,ʜL]rAYjke.+ ~鶊,w]G_)W}Q}Q%oz]]EY3>.<";JRg,T~ciq@k7yĺ­̧ײթ޿+#s˯7 }ϟCLМjS#ċZ#ŐSnDr|&˚0TY3"Hth.[4)N_6]tͪ@;*jѮY٫g{-S)ڷ_AXϴw"k/رkkׯ[W-\.zƘ X39FLxrؽKg&ZpjɫݶNL纳Ï^6si[d|+p!=2"ƏC#ŎAYI,WNL)3#e6C0TicM#[wgQH#dԫPƔ:PF3buЯw],Λi}UkNC{ݱmʝ>kĂJfe?fqʒ oKZGWYʈ?*1ȭq',tl\97 _k 4wUm~<WR ul//;ڹq"g/?#|ݝCu%BSc$"җi !>M8h!4h!W##q̡+b0hG|nĸ/zA! ,2Ae@&diYlj*tmꭓq:HzqI#2iHsZrRYѫvۖ^5,cY\|a w^9n]#~A}{;5ooXetI7HM#.uz5m\'D&R:P7-ĭʏ_ժХ̯߻ӱUak$p]~H ˙h1C}zgNƐ A^<$cœF6Qb2fΖ^HSgp.iTwKqYӔBE*+V\iU5ɖܪ*SMNEk֭ʑmcI߾>W>im`r">ձO)~lf͌?*2ɨI47wa.ܺqѫ?gΌ/v߳E.J1/|,觥[ʵ,>շS^^zں/|ۊdzl#EG|@Xʀb2S6wWgapiu!} !چ)-! ,2Ae@&dihfh*tm+{cμP|qI+2_HsZrROѫښ^56F8ٝeS9~y{=6}-mIGes/)u$RP|55z".8$6t*U_:-é#ε֯%Ǽy AzRpa| Cȏ=Gqƅ!"{ɒ(' TxL֔rfL"シψ bhşP ԩǞXyT dV_" VJ6We}*5l۶;2cXW jӯ`joqO|+ZD 3% 9peϊ>4/] :ϹR>?|zK䦐'ƀq -Q~ Yhjz!8!)! ,5Aa@`fh8p̊Yiﱛ@N'h5@%U2)"Z۝6<sk+E8~ܾ6kd{pX~f/uSh?QI7on&9yj(g(:Ay;)Y^0|eʽ6̶Ը@ОҾ-ØmͻӒ䲍Ph\?~ꄵ#am Zgoa 1'`k3|x Y spǓ*RMm-HQ%˚4a%1&;9R2JJuՏEVD:򩾗Wnj@ajםO{6mӳ]K6ԫh˶oWojݖel_G ׽+ϲި. Y0hʢQk:Ƈ^yrm([ι;՞Ÿ+n3pȱ@٤շ.Қ`䥬%k3.^A4Sbz9Pa†>G#ɊbxrcFcdr^KbݜaJ8'sϣ0s9(O*k4P?fjTy_ִ&(TfUhصM_r5J\][շw.4N"6ܱe8/e=xo_ͅ*"w?NƖWKnͺr/~=vnɻr}s4{Uܵ{E=:̟{v+ZYf`W^rȣq~xhӧ>|$1m\ĀEG6yb TqJRTGuf͆5ruȅW)ؕ_N! ,2Ae@&dIY*liδ&<g (eV/ٻcH&n)9huFݾMU^X]-mh8$|L~r[V#Izx%Cu<|Gio"-#3t2{Zd¶_.0ŜʥϷǘ۰-׿ܽlò湔Ɠu7!tHBv.Mb@ V_/ 36D9iRŕE(M%oV_M@WfQD"9tiOG6T(T"z*VSCFu+Y_v=+ױhݞUUph.[֣߻>xa R`3l+dȚ-s`- lsKk6Тd?}|6ܨguM{Ip-cz3sᒉ#']ou۵qONgm.=w8w<cWyT[64.L/y-4WM7\0ʪij'^%ߛ$ɿp=#7@L}Xo=tWaBVxb>0#qdÎ A_ɉ'C;eQFRD%B s(P>i};RtZ_Ħ-Ji58FsYu'UBiѮf]{rR?~۳-߳qY ~xݣzE-7_J^Ld/GNL2Jv0n!lz/dԞYk^f؜6www1X[Ӟ1lҽm-Mweac̈́\娀3g]:v\m':_>;m!WK EyK~藟dJ@gÀ;f5P QN"RX(„8q`P` ,vb4c3=8! ,2Ae@&digtm*{樂(i oF4.aɧ'sNO뵩EeO.'KfwGm];p^wx;|:e6t6mE~4}d3HjxP/$?%/#LCuV0y(&p1)ٽȬ߾شB󗏝;S"4(N^ ^ǭUE {rȎINϡǀ&8e8-3]š3}I~=m,Fe]SґT#dҬî^}JؠF5,ҵ* mY,n׻pWŸ NwnLĎ!vbOWmx*K:)ڭ5:2nV3;lǒsi6FϷ?nuMdkƳ۝}کqʒS={o}Rc17VW zŗ_C*_AmyklT !aGT|d'jqִ݈ʼn(-"12S0֨9! ,6A`@`&fZih(p L8ފo7G<2b1c*}PWUu,-EǦ(Z("_a|uW]gD{'DbyS&\yibr|5T}:%%0?nHżvЙј؅Vˬϻܪ·FR)y;U9xݩ`?I!{b˘ϟz؃#A A6n"ɖE%ˀ0_i͞.s0F*mb9t#S~ 5ѫ:))SPSbmNBJ(ڪ)-JWj=S{&K.Ӽ['&OrَԬR綝pVv7k̎CZ ~ [آ%6Xˈou‹Qf,K[% 詋?uY9啳W>\xoCoX#sT=W=` aeD8ńU M/c"8X'Ƌs4H! ,3Aa@&YlB+*6J 5,ΜL]r%q*mA[+~fe2f6-/g=H{#a;}&Qqx]VH0%7$EsknWp3}@~<>M@Öƍ7.ΜJѾڤ"XŴ#̙ÆN?}#]}GAy 6KXB-bq;$4P;!=FL+]ғfʚ;}N>_Ø/dU˧,).ڴ%ҌPͱtzlVhI-k4nI(^nמA֪~[8a{{2䙐A6VUN-e&^XjkzZkgk+,.64sEAx[pl.74r]Nb0U3ыwz廗o{;j䯍s-˷{{sM?EU&`w-2aoaH`PX jLXdžu V(rH!y+F! ,2Ae@&dYfhfl[fz< P_&{&NɔҞΔFְ_U^Wb֣p3yD{R}cgMxdu'@taK9l#-p4qUX+~&$ħ<ʣP̰©'\ǃ܅w^nE0!à "4EאbGy $d$Ē2xrݥdeKOfOisg?2XRtӐ*5hLZ5'Sը%jM߶tۣ3 ݊Wu.i #+^+82Y;~X]"3嬓bbӢ>U֯=>\uVE2ԅ]OVܛ8цC79˰eSC!@'<=mS汞U>fG>.{帧\vǝIuHz $1{ 1% NaFHۇ rh!|fDbDžԹ,b=+/q#sƎъ!;ukui-biometric-auth/images/FingerVein.gif0000664000175000017500000003543415167732630017402 0ustar fengfengGIF89a.STxHj$_ʏeljA(8wʵժUCtFg35zWqf'سc~Us-h^]TjensDy|NuID! NETSCAPE2.0! XMP DataXMP ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!  ! ,~H11-pt^?-qlp<(}2tĮrq˽?tx\! b{)OS@nFl)n$WӖK ;g ["P A}2]#hhv0B/ʄfN l D)Ŝ jn ba/bEFj%9.YB{%&\=_*ԡu2W2&&fZ3E]gDىm-G+/q%IŐr71KZIW 2K:sɁ"4=h# ,*el)"Sp5D=-ˁ'X{UG7#rr|'8rD]tԡ/`Nϑ fL6JK :ɹ"EA!2rsPp1S;jZ Q 5o#S UPG#" BBvvag O\>\=Pb3)S=4 Ky rHи`琭s 0Y\sAEh3EEAHm#\ɉ3k‚)c@Zܙq HT 6Q$g4< P ˫ΝCLi1#>X6킷Qe4ؐFc`7"yAaQʙ;u.&;`@h2k@F!NӣOAb6Н @Rhwa]cfc\ bP v)'PG-nY׆6lX-2] /`O# C>];HcPmܺNg?prHM!x`MTME]Zv4Dp zQDt! (n@GplfZT<GXc U5%hvh95Ñ%67Dzr!!d \P×_R d9&\jb'FcL a 6V}iǟy!(]څ&Ģ(D*P)BQ6VՔ@ăOeao)*r15\L<ÃF%USUe*lN:&첏pI 7D{e.! , ~I|~N-?ȍ˦-ҼI|̚ӑI7⎉rI߶lH@7bZ8"Ĝh Cv ( Ce!#F f8q sgN6̌$ 2\A0l;4Tغׯ`rU3`ʱD"bM"Y Z+xMUXX̸qĆKlG5\]l?P1`E_] Vlkb˞M[kKښmBj_w(πs͠: سk.:ۮNqaߘ Ϗ~(#`YO`={ HEu[yf\ġb6#RL2DS_: UYU(UHŒ! 8PÎ;R@#88# .v ygZV[DՑdGTR K&`cu%'H&` 2dx Y _Y]eA٥Er,s@ ǞS1 Ě 2! ,~~|I|ƍɕ|мʈёI|ۻI8܍lӮ& !OĈ&XA*"nBË $<(B_̚k D2l@;4TYAE.ܩfp!1Add:`B3\ʬ3E @TU ҪU;,= -@# t62 ^êH qc_H~eȎUgLE}E0)aa]2~\m$ #߷mWvVl@ՈRaRk2'Ն~]l1۾_ ҫ'O^5[³F4'"xЀ )t]C B Nlٖx G…!d 5t vxˆ'h…$^'@cV}:a`bE]U GvԏiA*tmCPT %@`Cw'xQg!&i8({|1Ŕg<2#B꣄-q/ R衍RBd*EA)! ,~+~+;~+Óǟİ+ѭϷ٘|שEuڈ|1N|-lH|ޑPYz?)ǰC0b&2* {I*104ăM,Br3f,9ܕNSe99رACWUׯVBf*bhz1rP`B!j)R (.aƆ jYiD0-&2$NRz!0È 6_{lDž'WYm/E3q4n+Հ 7͛w#yr Al*[.6y"hʎaUvƝߙE D a$daÇ@|W{Q6}k䒀>PKA(4^3 1Ðv‘fClyރNaTp•'Ԡ%\v_jTj8a{8f @Lq$XvZ=YmYT 8ڸ,O$ EDRk&k96(BuzA D&\Xv^vF$>J ڂ6@BQ첾v! ,&~~+ +~ҵ+DȨҩж+s;E;ӛ1|NֲՉ|: k@y .@|0 DP%ܸqaU,d&R\iB pmΦXTRĈ&L<(]t wpl\B!P(M~7^OB`F$| .w@(v'Ԡe t`~eZ8aQl`S( uP=Ԏ#UE>귒iC]J!EQE [a)m&Z-zՋFBRyH '~! ,9~1|N +|+ þƃɝͮ+Я׭uەؚE:""WLTOD3А#HL@1A0!/VL ?.! >rcG 8q^ );w`S3@6X 7x+=A-ADD1g̼Yag@‚Y  a|JRF,+*~^ZSWe-XX ^Hcۚ+WM p_vP8Wf_f@۷Ƌ۵-;fYEg@/%I}JWثlbjeѓ 1{$қ_@wߪKTy/6l :q FI}ҝw-U6XEÆ. B{ןhPQxM.a$/L3vMF $=ۄ @B! 5TiXVI'@`|0,^pY`UACr0O#HX#>{cLwbu3j $c6 !%y <गPN)eVR駠nY]B \zhY@L(isd]01od l Q $B%R(C!Ctt찾! ,K~~~:+DE;+~uuuƶɥ¸ ؅ۥEsШҐsE E:D.jǭD%{GϹq|2:xkף !JlQ#Gb/sG)jԜ#8fLR؊zx dNT:41ÐD`}Z䊉ED]6eE)zѽVg]Ä X<(f"c! "GN@m 5oF{C5C Ŋ`u J.۷_ְC X 7KNW]4:D`r)`_H*_‚-Wlv <f[uNܹ"эp_bv݁g 2 2 VHa㍧}Q*ҟt%}%6[ 쩰 20W P ldɐ !Ҧ{9Da"pqp*8 I s ׯFԀyTJ*VCaEn<hW߿~ k#UV-'~K7~9رa%T@iF. !|-MBc5lN.Bfh֐t*(bU+hvk_j;S:tA!_ji餈#1ӃOy4B&>}2I48EES楪ll:T%Š-1%ŅhN B pp!D(ӧ#j?n"`:t;^X6lǏXLy2 T9 n5ȭ)WE싩j୅+ DA t xqʚ|~Cݻyv:?A!lږ0𽁁y0ҫE̛n|rrv7tVqfq^{QD9Tha$<F؞{}ʝA՟!R`"ĈӌO=WBÎPT x |I8aC ABL2y 5D)%RVO6 \j(q6(h:8QBwWQ(UJ$M8h#aB 1ßv |g A )x!9lɥXB%fWf$nf9d1Š `hkqyR ! ,g~1|N++E+|DD~~;u;ˈ ;E:E̜ݳuѬ޸뤐;ηtC-:K/- 3@b,WH u@FBOZJH$rP%K r@EFH̱gg]AA h*k<[<EUFZsM(:"'bիabAC/<KÈK`` !ZϦ6[E{I *,^Z5 !E s mfY? l[lH lxէܾP޾ xq6\p -(  ȀhlMZxvY4\:CuxPUw_~U00.3`8@E XFJ`@jPȆF$ZXm ˜g~ԩ8?H# !y !9g xI|yg7#`S VX-%VTuE֖twv`v~eZMkibʚ 6Px* oJ[U! ,q~1|N+ +D:|s+u+sE̞Eǥœ͎ܠʹđ݅륗Dóu&j`}~a3 !Q= $!)aD?BAI,n̈蛪#F1AӃ r³'O9MAL)d #LCDU0VWZ+hk !ARE1*N!38ѐ+%PA؂ÈVq`ŖE@툶Vnnݻ3} 0 _0׭p0jVZnv.ԜrMQl^Zس3ؾ=lö!gݛ([‡_3[p.5w 0x Duym`i`Go5'(URLuUTT;F "`A}1`H‹!pŒ5pB8R<#3‹$ Xt_a6"xEYeaI(TIƤ!Tvᔓg_h"}ƝHg''EHH&c]UFg,aC'u! ,z~1|ND+ |suEEęžu+ɼѯө DԸۣݞsޮǭꜥ"Wh!"F@@11"ǎ BL@2E" JǐS=K6 JY @@v82$)U9l[HΜQSQ)R)lhp ;hR %UKˮzkX pǐ_l` e2h7У|*߿XbMrFag2۸sߎ")W̶B5Ԗ"d-h Es< Qn9sq k#4^w!*UV!ÁPTp]v \o-0ą'p 5ta5PС za!HŠJ^oa w*RSR)%B@F$QQ g`g 5E!!㑐'nXi$$o [SƓyŠ]XaJ$h ! ,~ +DsEs+D:ń›ѩϐuܓڐs߲݉1|N썮:ʞ;~uk$h|ʏWu[( ȱǏaTuoAD>) 4u#աyj+7"1s@ѳKi4ebJ:)#4%AB ;cװ{(M4O ].#'ǐ."Ŗ5mrq&u`iP* ѪzJ*b`MРlYh=Plٱ zL+VPvq:[vhPp XckaqAлX38E @TVa ]{6l r#:o zgB|ulh. /^l`ݽU>51oHki fPo Ȁ Qz]z Xp|]Y|aX`(.b+.b:z)geLEZT^}VX%ĕ LaPb"6d@w&J"% ! d`ly&bो*&(Ag 61 `0q5֑EF5B U^iiI6AkiXfy"QĨ/%+Jcig[ Vf";ukui-biometric-auth/images/Other/0000775000175000017500000000000015167732630015727 5ustar fengfengukui-biometric-auth/images/Other/16.png0000664000175000017500000000121515167732630016662 0ustar fengfengPNG  IHDRbbTIDATx1nAoVAAN Bc: uLKkܤEimerGYA$QoS`jM@C k=El%0&DBH a"!L$׍ p];I2\_M6DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH}c&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH.7M'L' a"!L$0&DBH!5b~yqQ?U\֛W/LegQWJׅ90 6lϸp^lIC iqsݴX6ېy]HoD+9|IENDB`ukui-biometric-auth/images/Other/03.png0000664000175000017500000000326615167732630016666 0ustar fengfengPNG  IHDRbb}IDATx흻r\E9{!Bs$";!II7@1JRE"HKU&t-i/jokjvWM\<DdOD^o9cDqҸ _VHD_vUn _s_8mn;J)Ddin|u(kȕR'~ID<=?ի7~pDDrW[.=4EhD‰' Nv0kʯs.TwmhrJ k{crNj 246 't}$f ~/Rf15)q}}h}߫a:3J4o֖rdAB&Tco>sOx`6hgY`x0˔*ˑf>bmbҘsO""_Alm= !tAGd)vÁp3gȈګ3%ҔЎ~p3ƶ[(S,QS 4˶>̹zѧ1Gr.I G}*= ZPإJ~&,nֵg]~>ʩT*.> GA`|Cj{:63!Fixm]9L~I+r|_*Ɣ_RX/>sg[}wyƶRJ3)%w[' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰'R˚&<pS|xG}TΦ̈ƾs&jj>+hc'9xL٢:k[Gd[tK,5λ-W5fTut`:L_:ހ_/-Ie..g~icvS/Y?--Kt/%Cm] Ed`[e&n7p}`Dys/9p6>~{jEEs iRχK>x-#{ax.}z3u P&X `?g܋""2|$mֳq2b e gYe?xf)-ccRX&hMzVlCMF wG"|btQwIDD么PaO%"g+I\Dj'| o\zOvE k}'7y4CcyZS az ~DccWS} Hrg ]"*@8QpD‰' N *ډ>}+1 wm5xk 5 t3Z,t0榭}g{X̓9df |0Ԩ=ا@KS Y&kwbjk}m R ;LD&(85S,R&\ϬQ(/u;QkXfآYPk&0+ZȚj{MkYl5*eb>#E ek cVLC=hSS>0߾rw~i33۵72;>(ղ,dAIڍˣTe9{\, J nk_h3FKc6 w2SxR

#!m /g0u=)Lv`=k hKE9ǧF; {eC#HU!55D\9G[Lg|m!%͕1ꀭJhu_H"LD0!Hm!DDn1ꐉ!æK: 7` ŝwm<VjF,B;n?kbDt+/P}eU ۉ}A77{S<΄NϞnUw3k}WU"0]R8 (5B8a1bD.mfº5h7MGv-/ 3WwBT=3SZ7eK" *BЦ﭅PkVYԀfȽ筛jw_MvD0!HF!mj7vu&5v^wi꾺@3,IahbȴbdH|ס5Fxv`jã]S4e.8s) {k*e/Oo:wۚ&'³|MLR ґh&D$>?b>o|jn!4W=߫u&irAZX=ٮij}5mcFgC&F~NJZ$ņ 19;C R ҃'"dMr* Җ^>aÐ(m3tX"\rD0!H"LD0!H"LDX a[/#Zf}83r2IG÷>`8(vtLܛYFp?{Z>ýref=W +Ԣاa/R7JY,kIENDB`ukui-biometric-auth/images/VoicePrint/02.png0000664000175000017500000000234615167732630017664 0ustar fengfengPNG  IHDRbbIDATxu0=l@6H6 $:d@'H:A NNX8`l¾{ R DDm?k ƊFBH7qqm8oX?QήBȗ\{ 2mc Q20-gRD7 bk2TϨú!Mh q)F4k5LD0!H"LD⁈r>F0":lM5"2ts.|жžZ2jwS^|Tۍi&e6jb?D4w=_@}e) 75<# Uڵ'(ӧk$]*1jwyh[u)ڧhTS]ɉb#8"Ԝt$"|,h, 4W@ze欝ѨA#ϳFDj.DٷuMplR6 ԀLR-h=k]d{"* oL7,ŇrbL'mP CYJM m '2F0V Gd I"LD0!H"LD0!HO|:?b6k0='tyFrmW/Cۛ5X?g?ܫIY{[]SԦva[qSz,R 7.#IENDB`ukui-biometric-auth/images/VoicePrint/01.png0000664000175000017500000000234215167732630017657 0ustar fengfengPNG  IHDRbbIDATxu0=l$Nv N@: H'N2A L@8`D' ~D}:G:Ye"}ʔ: irrz ฆ"/2xD&އ W.n+a_;۸ζM`.{;kڱLiǺ+1rj !paqBEi ?ʺ !'d|lc`3C\`BSvXͨNP!GCIW=BK)c[3v Q& &D"`B$ B̈\+c!CnEM6Iqyujn+w\NX+x= %8 %o#zMHDM|Wf-oK Q@tnk4cJ}:=$ߕ:` ͘9> B^#v̿hDDKl)yF=f~Q#FdFh^`vI!ZvtッS\(ih7Mw]&o`{ olCME~,@iʼj w_MjD0!HBVnN6J{MkaoXιP0cehng) h3UX2$~֡7Fw`jý]S4 %]aV4$BkD,g?mGy&'z>q'PdkC8T#LH2ߣ|Q1á)+X%U {TA϶߻WF8jDa]&Ìt3/}Kf~##7"l*w1B b.BBFy'4n!(=4g.wG="\rD0!H"LD0!H"LDX a[/ p %]fܶw+>f]1}O#8ßz=.0q\iC߫q Z{"n})6 a5?)IENDB`ukui-biometric-auth/images/VoicePrint/13.png0000664000175000017500000000235115167732630017662 0ustar fengfengPNG  IHDRbbIDATxU0x N:A B'N@: S,LXX'+9tɒy8p/?mH0'W&  yNczՍ]yo8pg,nthA~m bܴo#3sߎW{};b$4v&>$~UB.pe{'l:>$DoouYTDM1﵎gk*gԉaa%*B=BL%<m,CvD$Qf'VT#6ϱAk9~Q.hh紳!vl|D&*R!"X*h Qq\Σ-đKr&`k!cL0!2"LL0!2A[""MĐ[aӥ}R_^ckzDZxhkyC'R=P':ښ {ˀW{d&fKDErwWf)/O!ID7tnKl rǽVyL퓆:k_*t"4!C""f>Uᷕ-b )gQIZpzH/h/0;J6{Jr}HD yL* 7wNkR3z ]ؾTM5!{VYXڂfh*oFu[[}5a2" \mu84dr2^Q=Qv aoM'hna!|a٢gFN!U[z\//lodu7M\p9o-.%o^~/:Dǥ_M e{u| 3ЁM'CbB'4*}7iOc9V*|;A63?YBx" np !Nf%;A:1ꈊb莦s!ݱ ѽ i{lhԜvd9Ze?F؎OMvN;BƊG$ B`;k%L\ѣ-D&鳲G[ Ise?F5Si`ݱk"`B$ &D"-=e?F21VttTZ;z~w*̥B\b{ڶwSTJF6xfyK~Ta[/[kbDt+/{,D2Oyzx*5}Bj[[mf㋆:ǕjS1.IH$!3Ҷ?8vu!D`kb{CD_q!v4.?8(%B8c";*b|- ̮h+uYЮ;=%3f~ E݇/#D3?!mkWMwٹ[yh.6&MS ?ZЬr'pc'FպPレݰ`B$ BVkyrCcIwo{*|wҴu_ݎgӁ"gؐØ*Ħ͐LG {pC3Xh'e4UM%ZOEϕ4Bd{Y"B;%* j3e{_DxO Ijt$J mLQ1/Rjd3ck3IMѥ|g몦gF8vJM1!A&i`tȎ Cc1gԺuh#>HwgQVZ(usE1BrҶ8C2=vapoiH"LD0!H"LD0!¶'ΆfdnNh;fnۻ> G63y֪W^~/,{\+We5J~/[~ދۍo??"%Q>F%IENDB`ukui-biometric-auth/images/VoicePrint/11.png0000664000175000017500000000236315167732630017663 0ustar fengfengPNG  IHDRbbIDATxu8g|@@ [8H@Nr*1XLVpAb(";E @=]DQN\O\0X-'w۲jl}pfk-nl^yw:DǍM OڸЎM )W""f"vKi^6Å+}7 1+*| ou%DǷ/V;n!F(ǧ&; {ec#HU!P1P"tţ-GI |&`k!cD0!H"LD0!A[G""MĐ[aӥCR]^ckDjxi8ok%?rr|OWjF({*Y(D51"Zϱv_x*ľs ~f쀷N7m)vy3Ջ|ԙĎ`\0wQ'3!OT֐r|R F3f/b~EQHŢJ!ڀvSə{`7$$E|t V#Sy5XFM鞺~,4؈}nkԻ&B7l@"`B$BUv ^ z*|wҴu_ݎOӉ"ɻ}7*DfH&I|CSd! 74|<# MՆg)ӧi$8\BvAמ7W+,{9Eg3$fFD~ir"SBd&[F[0!"[ g_HzBg ?,0 i.Xg=*'Bmκݴ!w!:Js Hg^4t$30#oG h*5)-FcAڨ!".*ihrI8" 307Jf 豟W&LD0!H"LD0!H"B>ʡlg&N&i~E8mW;Gwhr?gmW U t]S)ԾovOgoXO=?ʱU`TIENDB`ukui-biometric-auth/images/VoicePrint/15.png0000664000175000017500000000237715167732630017674 0ustar fengfengPNG  IHDRbbIDATxY8gx;t:ી `+`pU U@W{"LDP`Юg=Bdn9z4Whf* ?& &D"`B$ B<UhC&܊.[4"R3pǫoC 5=mu*5㺲)Ğ -jbDt'oX2_U먛}Aj:[2|w8w_B;SGM>%s93 eWlRٌnMQ'30"M@ !~mg3JBD>".B^G+*{)A3*:Uc{Ae_94>0meT4o7ک\lPjBȯ̭fͦ)^,́᫅=P_M~D0!HN!0lj7OvuݟQ 1 U _ݎ@3lHa`beHvCs! 74tՆg(ӧi$ы _4nEyjm+'jI]^8~y϶jt49ġIL$j&D$>2l``{Klu.㣨 ? UODMSi#j\M1?c8D EG*||-Af tBe5}GHu +}7 #8 yFi î=qpoiH"LD0!H"LD0!a'mOpfdnN\I`ۻǕh`{F{z᯽^Up\H5:B}Ke"EP oARIENDB`ukui-biometric-auth/images/VoicePrint/18.png0000664000175000017500000000235315167732630017671 0ustar fengfengPNG  IHDRbbIDATxU0x I'N Nt !Xqc:YO O-, kW% ଁ"o2xiQn#+[o0}{ 8&~7v+ok];64_vl?cC#!{BUl| m8nTߤ?g_ٖ]!S^o>LJ(ajGsZ >BzjF} ubX3U!QM!<}(};{v(b3IebȮs@{V/U v2G$ B 45LL9G[k|m!.$͔1J`B$ &D"`B$wDD1!æK:u 7Ni-pn{)MؚiL9_nz'3qOO_l7=JB_}"FI:Ѣr!,d@iz^FJ^$rqNh*c_m(cZ-DFD頿W7tEDAsT|^Q ՚&Z ?kY#2u#|᫉P[<&D"pP4۪2]Ce$CM4Wc3:PDs +R3uX2$>uh2D&ʎ3PY`7eT5MSIWnlľ#BFɠַ̬Dog;XX49ġLIGP0!"_!ns|Iw/`:kg !EjG|4վ6±S#nwP HJi_qLHj3Z3INz\` %8ۙmw0Jao3tؖ{~"\rD0!H"LD0!H"LD a[/ʇe]83pN(_e`ۻǕ>f+GYFp_`Y"ˎW )2lv+n`MGaضB-IENDB`ukui-biometric-auth/images/VoicePrint/05.png0000664000175000017500000000235715167732630017671 0ustar fengfengPNG  IHDRbbIDATxu0=ـn@6;A h'H6 $wq&H:8pmcN~噀9Yskˌ Yzrz`Tgp`ȟ?PoӲ{9 >JvcҳAq\1nq/<ދqR/ DD};6D\툱hʃpvFM:~*o+;AmT%#l_/ut`!8~X~ j[BaiODkZ j[Jܒ,0SHTu֮h _Iۃ.$*46±"j#3!PV(~=[B0+ 1@;(W"+8N\ZNz'] c07Jw:c?m9M"`B$ &D"`B$ &D"-|ms>83ڌnquY`=ߞ5[`G3;+WfRvVweE]xBiX \IENDB`ukui-biometric-auth/images/VoicePrint/08.png0000664000175000017500000000236415167732630017672 0ustar fengfengPNG  IHDRbbIDATxU0x p'vA N N9ŊIllž{y >]t$+D&,ʜF yD9r0gpas?<Pn[+=}Bvg_G۸Ѷ}~S^7۱`*e@DܷccĕIߎkfM`mpܤ~@څCeSBI.hmMB L}{h# MEH npɄc^xNR!"LLP`Юg=B9z8Thf*"f &D&`Bd B "pфL 6]'5֩GfJ>t ,1N$i5SAFmG j뽶|FUBWf.o! az?]йg/ ojb_-v0ZgG UòEΌB Uﶽ[2_?wF8rg7ɑ ~mijru=}ީj,^`[q,-RT pھ)IENDB`ukui-biometric-auth/images/VoicePrint/09.png0000664000175000017500000000233515167732630017671 0ustar fengfengPNG  IHDRbbIDATxU086 N@7N@;AA $0fo*N]YsN\)dIVLX)K)-dz `Zfp`?Eؽ5yOmo׎-=u4 FN]`ƾ5@Dd1}lX]%ƞQVaM }wn'!9Tvo*ii o+$D/vh!C3܆h7ބ`cvkhW!V S  ?͑b }*<#W>m 3X؞X&J3/>qo5勏q d<<΄Y1Q۷oc<۞1osqHc̯.hÏ#amؾqF0!H9 "r!$B`MOң pv/W 5e gjvK R1?[|P!"BP樄m{:],4aWiXAFaijWx THP!"V۪z@*[PkB6Y~^Rx滣jw XcWȢy M Bl  h_M+T# 3*Ci*`{E %5gp?L"nQ{mr$ֶ. R )2o{`i"A"THP!"A"THP!"a'ng&}f$n(c}uнYԾޞ}xOEYzԶܗ#ۭ-/R !֌*v,IENDB`ukui-biometric-auth/images/VoicePrint/10.png0000664000175000017500000000237715167732630017667 0ustar fengfengPNG  IHDRbbIDATxY0x6 H' h' t Nt X/NV=O9]􏤳$D&<ȣ-K)ɕ56˼Fyr-\8 R^y/W=:Dǹƍ wڸiߎ S)g""f#v$4cpv&U:~MBt oU$DOvtgo!F5Si`5LD0!H"LDbEDZ9r+:lOklSHpc<b?xM|_):%L 甊Y Z)=ZF^~5|eU먷-8{vTSe[| HκPo+7釂S""fҶ?fDjD#`GF" 2JNGb7:X]P!5h7MRch/7-D&2=m}b"x#DTjZ$2Ϛ4kD=߫Y1W [[`B$ BVp dڨIo:؛^wi _ݎ+fZw憢פ0T0d n2$2uhl#d Mo;C]gjýS4$]ъR7*~ƸXBȲMNFڿ}[Dx'ۄIDmM5„ć>B&O(_ `Ko$ lH7XtUL҃ Hij}6m](݇C$8YQ{fre }9سi1!(ND)(vf3 rҦ8CM+zߖ$ &D"`B$ &D"`B$F'>~Q1=Ù3t}DŘmWOM#Q阸7˳|õre=)jWE~ ^(6J{ 8BU݀IENDB`ukui-biometric-auth/images/VoicePrint/14.png0000664000175000017500000000240715167732630017665 0ustar fengfengPNG  IHDRbbIDATxu6g|nw@L T i++X Tp0 Dw( q {ו5Mࢇ2o?Pn3;7]hp#eq7Aqmd/{0e "bfڱ)bhG^BH3~q.lw8oVIXٗW!CnhYڨ(!Jfx{b?' bB]zjFw ubX3!M!<c(cqD6Q ' FvmAI*c4d紓!tl|D"*f>c@F\I+sh ISZ\9 ؚ4{X5LD0!H"LDbCD^9 r+:ltHklӀHp/ 0-Wbkuf op =~R^~u$}Cxkdb2~ PPybKf9կ s*%=#/Dվ Q%3uk"ʱT̳oѡ(5Bb"wVĈy- n uYnڳ*zQfΥbH3gTk Sqg.%QP!(Ll]:47íf{ǽ)jw_MnD0!HV!ogs ^ /{J|vҴu_ݎfD3lIahbtbfH&RBO!Cnh<# MՆ')ӧi$QWcjWJCNG^)LkIn 3ś#>*V5MN|P'D&H"bL_Q1tUv=$I)PCǧ*Xg&W|g_'6V5M轢p|?#I+ސ*B0/W$b@c1g9`?bés&96A0 cC~ma_apoiH"LD0!H"LD0!a/m/0| $^aݶw+}7=4A3c?޿aGkV=+T}YA[q_&[8l,܇G ɻ@pIENDB`ukui-biometric-auth/images/Iris.gif0000664000175000017500000005671515167732630016261 0ustar fengfengGIF89a2nuw.SMlS iPpZ+폢ԩH xÓv[b%Sөς.vBSKLHwd06d,ۻkx2a؉kܦڙ۞y”c~RJ>kD! NETSCAPE2.0! XMP DataXMP ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!  ! ,~qqt}uu}tp}ƽss@@rϬoܧtݧoM)Ψs)@qf+fN:~3'ZCi@lP$;97Nz#/x%#tYj3izs/\:Sz GePA 8(9:t Qެ̷Tg}ú&ѫ0DKVQ}R}4\׶$j}TYSə;Q@2K YcK_ VeLsnՙϘj>| ӨSǚ>cTeu&]Aߔc*s䞜/,J5&? 7Ucų{Rw'jMeNJ1ɤ3!adq' )o ` >52MJ[A8@(R9Eay s[) Dpw nB"rC"@({gb pthf1uMxIuW6Xvf>N9PG.Dw$WI-#&F%x% "O>eC$$C}H@J!Ni%X Ǥh&MPĝ*B#QX` q6(¡eYGp=هqP_QMX$:ȕ#J~񚏨"q H'i!dh\reA">GƧ >'}@|X\)0Y{Htdɭ)O&mlQ 4" +j~&2ty"uNӣT)NIsUB:?원KPszYy$/0{;.${Ew/$TI. wHaJ7:ξ"ȌՃHK57~^]$ jȏ#wR?4ow"Q!0cNPcDax +$A? oEeص h"&ԝa*t[;G$p5‡n;2b$c "D 7a3+C|( E4ȋ-/3fP#'fLA#! @BvM-% DJ܄tBu'MF01C)UB:Ut%#JHj`"(\a"'Qڨ1Y>xla/<&"G ǤȉP 0\#3M3/q7o;aD9N|cdD$yi8QҺKCTch6وfBUDFC4lX<iiTÄ}(zM5KMO:Q!F"{hXW"+Yj"G,g.SZDaFXhE}HPFǘ3))A2"P Cp"QS;6{<@ y؝Lp]=(zȘM ) @Y0q"qqDo gT&:"4@+B|2Wi 1C0nzp%b[i#QWnJB)=MQ+=^"&٫}wE"F{-kSCa/G& q!"]0ȻɰWD@!^I>7\l׉q{5ڡx+\ E^4H@?* @8ePySի&jU|U.$X?DMw BY I4xP7UMV{0|3t Χs EVQuv };spYgm!`H")b97~{km0Y2w`8#Tq֣z@&'$6 lf!vؤrE'b uq`2TEFCT4E&PP;5F^*+FkĨFz;{FK8d ,Š+uŶQA0(c7E\5z,0,1byYˆSZHP& ! ,~~0̅o͵}}rAAA}|J7lw(!#Jذ(e6ߧ82 ȉk 4XKbʜĊ m@̣9!- FAk(- $F}BUR|aN ;;$ EF!(:3Ԫ"߿}ꥪUKb&6Rٳh e໥t+ȜD_CMР~pK^c ch'<\ rW4.ȓXμO;ucHȓy^.čP܅˟IOu^3O52IDQpY@^p-EUz2E{q (!sןu&&`>j #PG%pB^qrG*PFd*,)}(u"FXGVubH()9҄A_\3* JBYW>hӭeXp$Т[U ޞJ砅꫰jhS2 A%m`l~_%*=TT鍆2 h +t¶rz r ]G# ٬§6m%,hćkFlݕ 0䡱5\yB|T{<#+8@B'KPG]8T],SJa#AsLr1 hGn,(.[9C{Ѓ='xLG.D 5FLMXguB 6 3Dkhc녤p! ,~~„0ūöǿӤAAA痰)c (1(TȠÇ.\0<|)%T r;e! (SK0!NDx/e?yD m#%P $&}´SJTP!M 67N>!u'Õ,6-pʅ۶-S-SJp6:Ƒ g+\n\#LȐ}4/ʽrK>oV(•L)*X萣ULqaovf!_ItR &NKl&OYCßΫ?},fL1P2rl2on5蛥M2$}X։HڽRZL}'Cm]0Cya%t q}ƙp_~ǗU$uX _qG$sa#s8r]P% R6ax]!"F)`b}*ʐs4$M`RXv%5tdwYm*t$1 {w@ȱ襋G ]ɠYo& œ&LzSC 6稤jC *%@D%( ) >w&B b~F;=t0喜}mDߝACv ̠,}>½/~.+o vz!IG 2MDyAhW>!j(qPAkiz#r: !8 h5<x`=*S' 2 +n` ;~M\#1|5HhNQ !t1 1|ix@{<Fa8@7ЀGyFPNJ;tS Fu5hL ! ,~~„0ūöǿӤAAWWee(77/:aEi'Ar]NnFrʏL0ȱnjL^(ĉz !*P5|Mb ϟLr'NTrö'Npf80Я`?$(VNh TbBjֲNP|  4X B`9r] c*=vZrm=$!<VBëǾ@Dkc˞} ĩ6⇘ \rfIP9unht'75Dbw݀sȚҹus|9Y*bFXEWG ݁ $ p u ULp ge-gJ#rabt\ՔtAu]<@#~嶞'h}X\ ppL@`)rV\?иXh *h t n.G!ed(uc't\)tMZEC_~F}f@) jèjs uq /^8iIx[xpV ,žv)B[*vgpFF_V؊LXbP_/[DPm詨B ,P Naov&8AzphLSUeWtZfKD |o.ۯ0𳤂zA2_&{"9<2U1V>B\Bd 'tF0FaĿ+t!}w|;߀mA` bqJ!Qk5;J3(m}ܼsP@4АOHf&əzwB'?jʣ`ě]vه'aЫ@To C@jɷ9! ,"~~5 5l5- | iϹ͍H|-ҍ5 ߡivv 755aYU憂|)@䝼gj' !}eZQǏ =N$L7,$ 3iIIc`2c  Jh  @A6s/$etϠQb;ٳhӞ%K6":P0Te00Ud $rmBGi+(^xǐKNK6ˏQ_[{B2v27#qc$b~Bm۲eGf|6@0sO }" a–bٵEhoN[ xϞwbqtaPdz=1w2h &yO](Y؈qh&Q/Q`Y($t <Ślp&Aډ acIb# E╫e]7◂UGq iBp*xth'>ᄘ?'\h#X>hG逯#]t:< V;"ccN& | @冫cc4d*Ck b * Ҫ $`j2 2Al2b/qkI ZD_[lƾ)ժ aF) ?  4ϱ j=GN=K+%-|B\*/x  nxRa `p@A XЂ#Ƞ#V0B(4aRB0ܠ eA< .PBppV{ ?!@@@2lA*\ H x1fPttQM' =LKk[bԱvd0 ̡y)4 Th@. W"P<! ,.~~l||--H±H 5̩5| ō՘l зߟ-i煴 0%3푸d ѻ7Æ"JHC|EJ-ۤ^Zch!E AXI͛3 -h)dH)I (ffeׯ]jΉ<烧FR'$y-ڹ"j_+LF,!@c7=6ڵAhνv[><8,$;# H5/OA8UaOǝ h&`v'W705#\&WI7A_DBL0Zv`4x c<Ё 5ָ`څa` QY׈MVY"-&hg %pH PBD \'axm3E{XF (ѲCʍQq/(v. %jꩨ؉|I^>*&IRZp&h[1PABev!.1 2Cr#zg4H9xA\aXF-vܤTr[VlVx0# .*hp !t:n&P&ˇl2l2i+%& )@~6 HC7 !djg`x9%0DBQ `XW"ij8 ; 6C +PK U_-HCLd$>io,T̗^͝D@y =:|46G [x!8 ïG#4?!'@ Ӡn o0`GP}!t[DA\ŕ>t/_p RlZV0A Ax <. {P=*܀?\%&A ޷'  P"T"( e( @brΐ.zы*bU@2QD/ 2aE/,(;,҂XI! ,4~~ll|H5||~͖iԶѳڅɲ 0µ۽H- /qH$'o|<@ AXظK7B6\Fvqzj8gFQb:4K (]T),Drs0*f%T(DU[mۦpҀvڨA7/X;|H 0Q(n+l< ,q37!kbDP8N;!Lh12i㡐RLoE @<@kx@Cʼn3!NDoޞŐWGm̭kH-7[ɕ{? .}2OAv]q4u$PQ[`A v#MPB[V}`‰&t" 10C `Be z#YU /`IYwJ}%bt٥ Hc#i3`7ʐueR @Uiǚ0˄$Rh$zihP(,Ce"bi*zid,i6!x=x*& ]nyb~s8SmF'L3G rc/,EDoWJJ)_jzs27%`[Ъ %pG_~r:rHpUHzM L,^b:m*7C,j>}ѰQ5dx /!.^)C&3 خ CG `1 uמɻD :8{?,EÈVz91MD]7!`z 8TȝCH d!e4cX ű6A=G  !8믯ݪN'n|x; (EEZ>PJ G'>_FA+{`;yK`9~z@ '!!|j JF" a( b$#(v|D񩒈 HDd*8*vAV%2HXAFa! ,:~~H |  HǂĞˑ5lؖ-ґqߎܯ턏| 0vv7(VKqC>yε2Ii|e'hx%_(9 )3E{СN2}Ed  Ă20qHӧ"@P ?]„O65}ZOό5j![ p2x x=CiRQU#Fd)Vۧʠ*[ 23s&sM4i,@ .F 5 !_+BC,Gs ȑXNBDs:u*TvYsׁ-\;Nƺ Hc kc99'ED<  <7Frt\BJvV`''AQIpfGB~ן ,`(1Ƌ,r9]H}TV/e^'%A ͷY, h•&teH`v# =V !ER@0D^hQo@>F> $A. [BPЁv ;H6QF0 < 6 4A *ChDt`qЃT. @! ˌ[""5Aw*(x'>~ZE"p2@21*@#U6` o0C%\@ x ŇC'LQ^xxCdE+KC! ,@~||VV U vU×?͢м|?U77?vHvVMXЎC;K"JHqH $LAxjDRP!''\9NGbʜIȒ |8PܯY>)ܩ(!i ,py XkDA5I{K(e"}04ʦF.w4`䅋 L U+eOH5 H5ڮ;]AW=_&4^ͺ9 [7*Q"n̴sϡIW9 Nxp`ρ{kwZi&c*fp-Q49F=a7>l4B \`{v{H`<4 47A;tO8쁃'<B!pJ!nx+VX`GA,HK@ :,u{ %(4( ȇ {Syz{^}Ѓ4 Wh v0 @O @܆HoJ -@ buP,IZ` Jb qWF\AhL4Bu”.R1 @_R(@ TD?! ,F~|| Hlâ-;Ȭ%A,Sfk9xx{r1b/YS0f4 ǸA^:54`Ë㰓 W> @IGMwyIe:m@ 0h 6x9DN<1`WYX`d}V6SWөހO&~Gp/̈;L /bBOL7BwPtwyPaU'{Hˤ P1$!6 jVVؖ]:C/݆Ӏ4Ewc cMɗ!a"~@J ODYnF/&P  !< +8 /x!0gR =B_j!>ep9Eh9)@s`.::FJPXЁ΀v8H '2C^<@A Oxk z|@#xV p|k0Hin0""ZPPI؂ Z@E Xbupx` u02ha %X a{bB}hBD`@! ,L~~|| H U V×Vȵˡ?Ԕ<َ7Β뜐7KKvlﷰFe@ŏ*GHŋñ~ n#`Gc82&͘_4h`'̄ -!IZtAqKe˟$Hݱ.jʵ׬4T",ԖCv6|< x$C L8 L$ƀ!JAdYju1(QXc vkp4cxycf͆ yM@<νydžynBv 9ls'谳(1@y@Dx<F(a v7CpOH`z5BUM&[OQ ҥw Ä<6! wX aT&wKhUqڀDC  3l# DtKk [,Ո'>uن0*p _СپlڃLѵ,iAs9`ҁq V^50suvaG9ocF)H DRۉJ$ BC{ {?SL<@FFпկ~886xOnpN\#_={,!CR!Api}g@HA7X 2X(RbzmTE8X7up|O?OawE HDL!PH=@$,PH9l"! ,Q ||~~;5 VĞʽ̽ ӎV|˜ܖٿ(( 5;KC WWi ǎ*hȱǍh ō*!_F{vM4G.*F &tM'EuK_Ϯi&}!ԅٳhӪ]@Ҥ?,ͨ؀J \002kp(W0QLǐ#K , &dp`BaO|+@௅-̠6<|`O{>YEnf9JaeH.5!u[XlpCBôm'a9_Ͼ3c!Qx-x)T{M`8M[ Ex $W $B*bisbPs̸I z-96TndvqH_-W]`$`+6Æ$١F`B6\ȗ92k944E}I2I /P!J(qT~53HB2 T`=X0BA##X:( w nAG2(Sw) Cݤ)[( ٗ =P_A#tQ``/HF  @b UHP ,ȁspᏡKgBC|D ! ,W |~~|;őU|̾5? (HѺߗܹ vU״Vi􃰤 7K H0L;T\B>oh# CI2Fe H"m"b֐C]UL@( H-$KW+ZVN3j ,h pʝ;S&@ BQQw\)<T}D@&38ϝ׼Ȍ Ӕ)KN0DE(F +d 9{$_ ʆ f (Y vmA`ltGZۃ_@"?@5< 3H_e OG|iz4uTy䢞cemPV[,gp4_Nc 7_p 1{UHq^'|XVTifG #2ti—S`ŗhv)Î,6cVjQeUyp0Jb<IAepZr]4j̐CPZ fǥt.@j@gm>GfUN蝑+҂83F2|bCf苋(. ~٥gi 0,, A.Up^ :.zv6*hLuꨍj+ä7-wnvrع`" G '^Gp!] /`6s7ߌzpk Ă>J_aQz&CB™1?/t:Ǡl / 6xQH F hQۇe zluG̜}06 gy:wМ@1f^Sd;PhM߰ p6l9+' PBS-nFfA1WYa9J\ ?pBS0#3<!p@:'#T4WP āN@?*\@9H PH5`:~H'@ dA*d ' p=AoF"0XAxEN42A@F_EHB*J :5xa8#g|! ,] ~ |||7 s~ě-|7f0[VZIW܈~J0%L>%H$̎XܡB` +$%<ON b(x1qI& ŠF5Oln^ B@+9 ÊҰEFn!  T^D|I&?º%"//I;휗|(# PT",誂3, $L"ngPz'`7!c-A_3Wa.~%`Xcmrz % KdL/6ďor$^  # Sl Rmng]r]za;2=nf%Av`0B@G $ `nՋ@C 4*Ě.syTG ED{2n!`@0ax!p@K@#={0PT& kj`<$`{ X/KQ59xAvC4{H%8G~k x}AY`! ^$Є)Y ! ,c|| v~H| ~5 -Ğ~ iԎlH-˪ -ٷ離l|ݫ50BHs/Z>bKq2j(Ǐ 7j4+Cp`5.Q#H AXɳϟ;ܔĊajZ+`ؙ¦Gꪬv. ']E_%}p:1i`:+!G(yx>P*{n>*f7@@~hy, 첮|bG wod;w˪ Π6tqo d&ao,3qo:-@Q>V9|9qy^|.PC뾊k0dP"3͢9[}&nh54k1Kk{GUB% kad/Z6C]j,jzkv@2my z? C ^k1o%^8Wo,A3NA(̀>J(qPA 0B=P~Ax o!8B? h 8H =*p/{B! t$?$O/)h`DOzw=!A J6avUbZF`Fǿ!@T@u{",Z Dl! ,i~~|é-|˕lH l֝Ұ ޅ|50l| H ϑ݄JXȰÄA@0N~Jױmm B˗0YA)!a ;vZAp8nz9G%םdeFe@իUJ}̅aD\I~!W $M (UiW+ݻw߿ ̆[ĉC5Nk} m1NWڝZ/ $B~BiӢEk5S.?n"Cb;ej_KXУ?gΜ{`A$WI?I0Nr{&/; u27]uOf L${VĐxAY'A@,造 5~ua)x": pazWɄUT06&GA ( TiX0 +h,$dEv `M5(ǝw yqYCc:fkхY>裐F )TAfʤ^TiB=Fb'}Yy@}HttW }D`9аU j**C%PB@ -j؃r:Rt&$ gИB1 l,p ӆA]mjHj׮f}"+]@C 3o1ls +B Shb&Ll) !T"&P.j@kP\w}-*x+bWɥes ٞ^HqTI!zWn!J\:T 8N0>; ?U|3~~>kgJI2\8sэI#fv{jocAQ7)%z88$dj3˺QqI6dHFd:U}sJ4o؋ D"$\'Ʌ~MIv&,zO&|u$ V # K|d~IHҝ$$y+ ` $ D} +f^~?.P3,VݘԕtnČ'ULLWw]X.-,Wrxg@Vx|'`FevAƝ\Fx%K#PWt[Sw:MXe4]Sz6ᱢ?l[+I&'INO2ߝdSK5cV ZSm(Ɋߘd_R \_I~J]IIR; et$?ɞ|dz~$s IC+r(6 Ao%~V'}"?ԕt1*7KRqOq:ы=UUqJݢo~&^rکVKHV?#zNMzPzE:|I+@k<?:9\`zxn}o݈= < P I7   E 9SŜ$}/O:Kj{`*4~w} ؞oO9yx^+t2=uU{Eݜ<UnQOKmvJxzX-oY(E}!S՝5H&9|nh+ Y ̪z|[^$x Dv$fk3 m20!#5]1<> "SQO G"֢UPG&_b& U#fEF_XkE \_a-3?IENDB`ukui-biometric-auth/images/icon/Other.png0000664000175000017500000000037415167732630017371 0ustar fengfengPNG  IHDRcIDATH1J@oB",*fO,F3x;ku5[$V6a"? ucGNIENDB`ukui-biometric-auth/images/icon/VoicePrint.png0000664000175000017500000000074215167732630020371 0ustar fengfengPNG  IHDRcIDATH1hA1b &ED(j: m-Q!ba;AN0$ h!Xv""#a,n틄,|7ٽ;ED=GĵxUI=#YDQIxsUH^bm~ ـhݶ!6ࢪu©Ur_~_X`DT}كӘJvvbojߊ3S])AxlZ4f,F|/A^66U?YG\g|MVHJIe?iSS.c OU9o*z;%VI7}"FKz3`_1Uggb;Me:e]lI!H؄sYh&".E*xGDDSӤԅ%.xީZ!4rTFv*"EIENDB`ukui-biometric-auth/images/icon/Face.png0000664000175000017500000000155215167732630017145 0ustar fengfengPNG  IHDRc1IDATH[Uqx]IcL#m؉kjCGǷUd]ӎPC8[_W#tRXsީ珳dR/0OwH{Ôbl)=l &P=^*!n dW~`US?k. GkF6*l_ij)(^0W!Lju\z؄Ǹl% 4ih菈yX"9w*ȋ;"GĊVEGѬlw4:Wʸʜ`86&M̜F.|)Kס*'X>ex#a1HHE8<p =X|ѕ[Ɯx~JZKWqH$vA5܂ΊM1.<(K/"7K&WJܕUKhw-2IK8-dTWqq^iQɬ#a?Ე;Z)VdMi z (tIENDB`ukui-biometric-auth/images/FingerPrint.gif0000664000175000017500000006105315167732630017571 0ustar fengfengGIF89a0rݑv\Qkf }ʻ)`viաP֩6vC\PTc&䠾/Me뀩7#Ѱ8GȄ7t٩!jFp:~@}n,ltc^~ǀ pU߿ɺζ gR! NETSCAPE2.0! XMP DataXMP ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!  ! ,}J~}J;.ȎpJѠ˂̓~Ԫւtp ϒ>K0gV9$nj;sI UcaeS@ (AiGprܹV|v$(0 ereh4cDT VlZ* g@ )+,4R y*h\B fZmT gѝV GC䐊رf؂~Բհ=MڸEͻ] z7$\:Oym8S:>9ٵcRݻڡ$ rL)lkC2[J SU}E Ȁ@^PP݂!sQѩ3peHz04B'`;Z!"a;?i }H2 sH[Lb!E)X;#T?Qkظ %'RL)ȜH*%( X| Br}A]r<@KRWс(%1Fg2>B$!Pz'ǨuK :HY$`1a$"$s2 LXۈPet3H"2B!$D&c`H.H@5a30B@W=qL\I36\ :)+q' OrҾ)KW j6&+ /qt9qh"!%広Iuq)&UR!<>Le"L0-&ʡt& %v۰27up*mߌhf32Gg}0qkonе+0.D -_|#E^h4)G(.y"MDK>T;D\IbQkV jd$y(ԯ-w߶3~YI| $P9gGt`2`%~&ݣG=_~' U6 WXG0ӯylEuQIը HG`dZne$aG>+D=6EщMG#ʱEFM `HТXC.l$$ӹմtcIFl/{)gO._!+YJF|J,񊬤(F2^eleE?SlDxuL?:F0J 42$AP*a-RSɌ@u0\D5I# i{}(?Lwn6·*Rb~&$(1Q$(HbՌf}J%y2D"XћdN2eRFlFTq*!s:Gq̡J#M؉ |bܒ@rS\Yb`~4rU#tO֘f ;qփ@DjuGewon@ `A<Unmh4B8Ae20GJ`M2Xoeۼ򔶂6'oOl'7)%ӰM'˳}=􋈄840)C-i!&BMz ]*Jk 'qhӘT0jd90q*Ȇuzl .Shnn .. CvV(D/m`bѪI+7=Mzu4+ qb:`gA;bz@*:]lhXFbkq;6نÁ૙G9[̏X ;[~7hJ=&F񡲺EQ czd$y:Jd9>hDzW:=sV %Yrcz!GfGӮ򭳝n !wwڲ.C4w}<-. ! ,, +$$<G8YDƒ:! #`JQp;re\s\r*2 DvXB e Aąd8&th F bKĉ@P,ŋ/: 3b@X<Ək!d=YbNC QƄ+`X:" R0HȜd* Z:%<&VZK.YƝFf觓Mn|)uRYeVfZLbօܥf馜vz p Qjꩥ 5xꫮ B a뭸Qp +,2~B&l  ,kqC ~D-0-Q覻ŸLp\ZZlHo.Lk0!! ,~,}J í}Ʋ 999ͺ,,MMθLx+^XB#6d0az-˛<xA W0Kv`ߐt dl9 e&RH%T0}`de矀{_yfYJ2"ors>`W&A{>N#ꨂ#Pal(@d&HdNI94ф*@CCa,N1 lKPŴVõVv:`kEnFଳ*;1D®`M@Q.Gmp$ oEKC hÒSH" ̆l»J*j3tl,[껯jp )'L D Q44Rg V/A ZS]qChgQl?04o= |p/}6vCTC .H ! ,"~~†Ɵû̒ɬҎϙӏ,׍Ֆ _%F7Q10%I m `ÇD(Ç1| ?o|$v 7· aʜI j4#} Y)(IRBX aMRJJ Y<|gGuB"E 6@̪Q`"ȏxBG Qgf}ÖҔ@ 5ٓ ƒ0>T,%F!B@ӤC?Bg)by0ӯw*1*}ƃΞ 8=У/_NLkPedf@ v鑟 'D+Ԟ2}u!PzY#:;͹ " ӎ;´ªGΕ6븷֖빊 Q8ih ͎o $ܯ gpj cKJ8YM4a4PDL L0D T/NP\-d^ZS@,RKM+4DAtA`MUxⅅmodxσBB=DG#MtSW ma밿^ywNlMu4DWO} 7p@ wGoG {0~ox0aB#ytvϕ 0z ; LpaM(P>7XL4V,0(P70/}!ӨI 0ⱌI%SOYkg WFq<+_ԫW #S/ 6SLi1eAvXg:Qנ@CAD#@:$8KT4O'Wod}kt_D~kS~趗n:X%uLmU RaH@P`/ fف+kjw4vXA,P@?()GC@#HA\"i!O[:4DQ <0,j"0avDgl? P 7؀хUtl12"Qe-80@! ,"~~xqq5ƛʧͶѵήגԤݫޜ7LQ)775,,QZ|0޼C0)lHŋ0ϔkh@I  ɂ˖W8|1IҀe tx2F 5RQ1b0ӦF뺑kgF{y/*Ȁ l {kj *.خӰr)!'̲p 7w5<3PԪ~kB5CM 41# -x^ 4!9TPdw޹X FD8k ;&0>ev4iBM7I'9|ox A@|PCw .z-` /7C#xߎP8lw< 1Q36؀"@ ""ap D! `>؀~4 A @?EA Kq Qh?pylC 7(`1,D~xeG*"@ ȁ7qk Q! ,~7Q |QL050)xxL6|x"0Q0070՟0ӂ| qqx~ ~70Ъ6QnClPԍ|8a(jTd#@%7VƓDL0 ȜI&LFRJ1e8)TYSѣH*]ZSAqNҧ'1"3邯_s@ٳh5iZF-W;l ?\1+^ 371Q,A' |ޒ"^1ȞMvPeV^ dt$,8,hL2T ⣶@֪-9,O{bnT7=OAmhOuY<N%'"}F ]vC!,IC[D5 ^~ l@8Aƥ2馜j駗1APfDfwKfFIVB@jdFz0ѩ&r Y䃭hYJ!J+,>&(`` L˶`o (²0*AP{jvfp$6.YlA pD{B'ˠ,|r& "_Pde3%b irho( \w-3\OW" `foq;t],j"Ko)'#x(Č,|3  4BCS4M7 Ќ X/n/޵ʐl5 @ڧ& M7ѴW 41iSto& K,NPo?^HQ|׽!D^;ء bQl]XgQ |SX-8`(XFDؽ)8 XcAe8HIbr-= &5j t"b9‘4 jF 3@ qdB)lMx̣/@  . e%+Ip cI! ,&~" |)5q7|)qq)|xqx5L 0667LQL7"۲ )"0Lq0x"֓60AB T1~AbGS%CW!bɓ'q/IqX:Ǝ0чɁulY.|AI"*bbUjU4"i³0QLzK4 ݻxz( -v Gm Yz@˖ǏXr3ks((>6XEGlEKgqV%LoQcB ?Nq7lıi[W#ύػ60mnh#jTL/_!ٯG8/>tOu7>a VZf!1^| I'd馜nyBI$j⡈ 蕍n{zсxi)v@A$GVz:heOt EG -+!AJKc*(& -:A f.d,8t| 9j{ Ú.% a)jgB ($*Pˠ #< ,j-Kzb;Uᜰ;Sך 4}B(0 5| #h /lh*G!l{vMj8.<]2{B2=騧} -m8"8!e@im0 DKptǾ/To֫2/${(>'bW_ք: !?002-^p@K H z|@*8@8#@p^CB@MȁJԟMɇ\0?Ѐ3!" p^ЀL`΀$\0z "@&0p5a E{@G:b:X`)щK! xC3sRƇ@VJJjxhcRm!(GBސ>F ;~ɂPOTHI.\ QR@" IlLOn`/h+Y4/AH8҅JtbKT[CM%AGQw؂x՛# nZVW]Mís(Mzlqh_!(ӨQ#Q- ػSx\)+U܄t 5jJX~ KyP\Wx3zr#}CU-g pz5R <(_tAAs˙6w)dY ?ݥ%TU9]1!,-"O ]`h=CUWHTZH=J1sGB>(.\v0~0#I !U&$dErCs#H^ E% K1`:Fn 4唒y<+k '8ѷ {>:NȰ KP#jSXG4(g8;3% Mh@2  D$x& gF` @ *P8ԁv}>`"q H,B؃&P!r)LA a}*5o|Lcd Y0B: xr>GТ AHH@"iC2B$C..&L/mE" 0!EDVHd`0]PD~KR9EL2@! ,9~5 || 0x056 6q)77)0ĈLţ50)ɉxq؜~7Qqx57퓼";)`t0R0EM$"*Uk&b#<CF2 ]$oKAJpBDyX/!eYB,*5)=M*UjCDqu 1&PjUٳg m[-Eis4' aHYuE11V er&Cȑn@Mj&|)Znc8nB7Tͻw,%ضDswr0tMGkTލw+W!p!|k#gLLR-F\l챗^y>Ä<AzA@$ V%f[՟2%AA@߭yzd! q^@id?@d“RwaX(1V?O>i$Kv0Aiu 0ApmFi^ _qeT_&Y g^‘x*ꨤ APp! ~%my٨ A!:d?I*8@Ƴd0 l0A**ZQad}6+b}<?, B,'` c0d:@h{’8ԙ4PeWRPgɍYBRxryRbیh}3l o>0.wy>`4"4y?- b tá4:1uޓ>4]+TR vðh@2 aD '0& #/8 KX'PAtP CmxDTkX%D2! 5 h` PMh}@lpo 40<$,H4 h u 3b@D/abPC X̤"N|EP !+aFq*.ߑ.쒗.3C"8ˇL"K$! ,B~Q|q |)67|5 qq"| 5Q0ħ)0LxLޠ"x؎q)"ˋ52+V%t|["%3,~@뤰RAO cH>>!Hb'<"Mq$PIfɟ-%st@DD#ЫF 颮6мSBbC^,NB1eG T 6CD GQ4rW؋MB2UF"@|jI͛Dq%t`  ҡW6L**9Q>o<tU뷶jEǢn]xnĘ] o,[{m/^_HL9-F(k.qFߺ~5|-iASEr9 Ȟ=MhJdQxQw_޲gزTسc1٭SvF.sLiI&_-M?R( 'dy hg yM\vgDv+pB1 ,Ë/(/آ1XtlM^fa1%5B9 8`2•W~te\n8Qlqґ$I4qYt'Od"!Q?l92eFA_5a&A}$]C2J _B+_b%f+`g>\Đ*!.*֕Y*Jƣ Jƻ*``ﻸzہ Ԙ mۄ~m˭ 8'[*O(^J o H 8؋#,&cpl<`jVy m;ثA) u (T8T-`˫bP3 =kA_Wqz 4W|Rk C'.O{B}vj yf^Ǡjv xmT2 n{2nrR3_pZ]VçSJkI z-cp*~&7-loʨda_8/ TOjEppVA>I (˷[sXo-Zgm#nױ h9b9 -a#S 9<ߑ,\p2, -B(3W(a3Y'37M2l-9нh FWQ| _A}(gr5+47mg|m:|t]<}ŗg5!\q)'G‡P'"ÇUa"%h%Cb^ |&B& )ओDTRf9eu vXc<0h*P̏-_>@@(Y> f}pfRkbn VGΗAl$%Q" VN@F p!`b M`MdE-]uIEzg$<R,hdn b`n .dj Ɗr1kf k_= eRHg槇tI(-*.2p s<HĸPo|$8r[@f~dYlPb.zv L3=8taeQ 0=lp%Þ#Sn-pP`wK7Sau*-_TWK%6"vVBooO#`Ӎ2o.ڗ\h>[SkWokE{*Ƞ #D/;`z-nnޞu+\79Jb o FGhw9 }  7Ѐ#Ng{Ӏ5XOe,Ϥ5߭Se&A0!`3#@u@Dx^p&:-*EBz08 Cp+{T'M\W,`Tr*aLxBT! [42c iC@_\E.F_t f` & c_xk<F86k;eC ! ,^~~57|| 5 )"Q|čq6qxɠʍ"Q~ݣxթ70|йϳ dnmLP5O!Æm@I5pnb:|mÑG*(NQ%I G-4OkTc٨ !'Xtc{ H*5ɱ,~iׄ."jC1y5,*U[Fȕ+]Qjԥ~Nru̗Xj%Z}|.<9G015gF*5JJÂdF \{(܄o!1*ȃȑŷ&K/*`IƬ+F@w+KY/%Ɠ ^ +Hͧ5uٽ;hFAywAl|Æv!}R@ˆM8a~ Wgk ɥELƃH! E L6$>  )*> huBRS}QB AQ߈NBO0x'9KR UWZRaB m5YglxC ~ ꨤFYNJY__I'0JR+֥kRࣛpNd @Ʋ2 H`ؒt*klj tȊJ B+;Ӷ/ؒ t0! JB*ڙ_K ۣoz:'x,Ӣm- ,|֢>ˬ +̆Cow( ر h-`2d-O *ޜp 3''qi.n~t( 3(\'^ӎ`VMe/mHp}]N?-0'5ᅏc0/ 22d0 O ; ޷'-3d{#QBZ+L `| H0De 2`@ ` t@y|H!Rz/$a I p 8# @b4aC(Ch;ء Հ(7AP-L*D0"82Vp)[ pC q 6H-tNhX@HB#D0ƈ"Q \hy^EL)A+Le l`7򕰴*cZZAM`!\ hp&NHD6\ǖI`Q~X4L䡛D ! ,g~57 |7665|Q~66"Qx"0 qè57Qx760"||5ѹӇհqx"Ρ.%i*z[-_ T)r2M\(L`$vO&Oq*#0oa5#Qʘ@¬*MF*]*FM<ôj8Հׯ^%1k-{*Kn]$[n1b.د[ep``WK r@/jư\9v}"a҅&-^#r,>܄Y[ o|g "Â<1P0C f AB{@|9@#݇J~A6Q@QR@!]va` *UZ~vxCuk) ĉFwPPŘslFi~@dk,pb 4묱Вç8){Nj]D@V+YeHi!,Blh8HJ0/|mjE9pj( ] &˯ ܫ,(l-B*+ Xk'!L0Q&÷Z%?1`<,)<ʾ TOW2@ LOnpXU? }w㎙K4 *Ȁ/'nWu)8<A|m&l[Ͷncto|7KBW/0^T/4Ah|y7M!e!/Ѕ g0ȡs@D!z`Ѓ&!PٱC$SVf .3d@2Bo(6 /A .QS x:6т|xJb-*! ,q~qQ||57|7 6"~5|q q5 )ű6ɒ͘L֋L0Lˉ"Ë)Lq"x0|x܊QJHFVL:ٻEPm(O5 ŁAQ^#N yhj09h.8D܈֪N0SdjklHӧ %0@*էOmIc&УŒ ST]d[LKW-|˷HQJwa9r@H["K<9$>rU} V, ׯ@s 6ٚݣGV]{5+VTQAu)j\; _kQBڪǑ[VatGŠh $$wBzі|ЗEZ~w >u0 &]@amjYh@|n} Zn"nG" Rt`P1\ve0H#A`ݎ DdA7d-"xOFGhp`j衈 e2ǃEhYޅp"'u(b%@蟂2@ƫ2 묲J` ^(PD A`g*M ܅0⧋YDM`b~ȓ+OnZ )m-N" U _q|Y.6?ˏD >a`G ZSsiYpw  a Hсdv!Gʁ^gmRR#uA p !!ȡdhl L6?q H!z)؄]Gmv(? 顒 ``ix$svApyul`1*fޘfxk^ @!gl!*j*j|Ωh%ٖ( mDꝎvȩ8dF+ҚjsbZ+t&wT=/}м O<D_F4H10Lt!< xC7/z@o :X,B /\CfH!?"\HF%68iC! ,q~x607Q~|6q0)"ɰQ75LƔɐ"q ١ x)LrGА75 ^ &XD5 ~8"2lлՠ#J?"q$b;ӑ[Q|ePWX`PJmQ_ :*HkIlIEٳhӪM B5rEiTFĊbdA Lp 'EX[W89wNO*N8 A?MiӡC7 ćc2%YYI*tF~ +_~) qgeX{fMzo)Rg =oߞ?|CO7uA_FAy)|!DVhJ({)W\F@hagSzG]n $=Bq@)~!yxt#RW}w-X7"V$ɤq#j³- N m 6(DRh雙 ~[,>; +ý[/>۪Y&Y#؉'ĒޠX */ { ,*/ۖcfʰÕA,ŋj+C#mH2/,# /D 5t-m-aanp@ aǍ47iԍL! |0 K;1# /xxQ^dS9@a 3=w#sQ K! j;d" ai}%@ eM7ꨗ^z=,:{ι; so^XkF=X_:OCȎH0Fxm( /])F1 ӄzmysh<mn FDlH?,p;ukui-biometric-auth/images/icon.png0000664000175000017500000004472515167732630016320 0ustar fengfengPNG  IHDRg- pHYs.#.#x?v9iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2018-06-22T10:02:14+08:00 2018-07-02T11:05:22+08:00 2018-07-02T11:05:22+08:00 image/png 3 xmp.iid:d25dd608-d1a1-4345-8aed-f31ffb97fc5f adobe:docid:photoshop:bf20e7c4-7da4-11e8-92f2-d9e6550a8a6d xmp.did:3a170e97-9755-d640-8f8f-3f9b31c0e3ae created xmp.iid:3a170e97-9755-d640-8f8f-3f9b31c0e3ae 2018-06-22T10:02:14+08:00 Adobe Photoshop CC 2017 (Windows) saved xmp.iid:d25dd608-d1a1-4345-8aed-f31ffb97fc5f 2018-07-02T11:05:22+08:00 Adobe Photoshop CC 2017 (Windows) / 1 3000000/10000 3000000/10000 2 65535 160 160 4F 5 cHRMz%u0`:o_F_IDATxMv6dnm@ :i 4++(+(= T:hgVPh|^V4HJust; .7}Cހ坾wl叙uM1,uz뒱Wd f1,bY,X d:;NDH,FSwS8W"OTd/w/=*2)Wps C( ƴ! [݀0+@  9]n5r8L %v,vK XXcu_@ƛG1h[߁۱.b&k{q)/b^Em Ja^Xhe+q(,]WQ :. +K,lCyU[XRBTWJ<x<GJJC+W"u&/~%źebY,巸>A]˸VcZ\6ȧgƟ,Xe氟՚LH/y3C* !8׵;x&rdBJ+~'wț2nN=K8JE2r޷\YD:x&R=!jCy^ЍibDȗKW!.^5!sкTYV' ҥ>w, O@%̋ņ[e|'_ dk YIx&"۞!_ry`r@Jv4;x&3Q-R?`v9; o0з%))K] o3d_[8P2"rƼPӠqDww?n(DXHyLӆٯD1`=GqޯDLk# !uyqAք\.jaw<|+~|#8k3ynrNn*jJC @n3yq9hZ MWa2BS@TAwdܹG a]bJd}!U~* ԩ3`p:Ж,GP/g^L3#sL<ԭǧi݃㼙^HV Q>#vf%kS2 ]Yӵ}F0*" Z(b\Ur7 /Y%UAe06wW7WL׿୑o&|j͡6$$w h$5 0ԴYbLlt47)ļύ }wlvW~SQ3م I#zϖ1YLg0S佰P~Wp-bݚڡ~0N3Ɔq)4pu޹H+62#7dba|{v'=^Z*t-vDa Ҟ&[mɺ?,S,6`pU'f=`1zWN*SoILs6 k[݂uVpja-k)RX? Zq`]_ &YL@|9 i -* V5.xk0ސhpKNY ba M8n',ePasK;?`٥j9Fs0txNjnNB ִ !h 45κ-`C+@w!}o?W,Kk+,*[Z?%Kpe+:if@,fb3>4̺ksvU-mlb`ɖ2'gmTω}fOyaX5"\doDW8eu1$~e=.k,q hdh6iua,!?0wKZ-]W#~@#?ԍg4;S]:?HwhIG}4$K7i3&!E}6l^#rԏgbysv(C^jI8Fa YkCd9ޞ~ R?ҏsP.v9Ѐc7"we<i[~N)IN|:Upk67EWVzQVGХp@{!Tpmj)Χ>ul pׇb΋jeۀ->p|.;AWKXz"meրW2w<5]@=?MLV`n9tWfbG+I`c9k,aY^0l}K*,]3 >w*$1 mدD<2azm)s- NH6|SVib>˚"y`ZY| ;:s)Fp6n/@p~#u\|>xxI 53|ܑb7]QuDTd3L(^%o"9,Gfݍ֢,mVa0#M+켫>ƤyU|H Ͽ1B\$,InaMVFaہ/@T؎JvUZ|KWXVo:h\VٝhfR 3b6-sx/$hz0.x/ 4l{0 _O/})}@y}nKcA]HBKz0-|D^ao°o2Aȅh'!bY @d1,Vɕ6ij+~ X -F p IENDB`ukui-biometric-auth/images/FingerVein/0000775000175000017500000000000015167732630016702 5ustar fengfengukui-biometric-auth/images/FingerVein/16.png0000664000175000017500000000535515167732630017646 0ustar fengfengPNG  IHDRbb IDATx]n\IN۱ 0CD@@q&Dl'x%5@$$bH6Hh h`LJE{nu{O;TNWyv~'3$]]1p(> FNWzAGD}n8 tzyhIkRBs8EڶՏۡ]0ck< %g浚vۓmE] \aJ-e kkԑĹ3o9[Si fCHu'pL`-4o77y'8m Dd2_2o.Ci/f j'8k'rcChDT:!ܕgz޵胂QnGߴ=Ӣa'{Ȫek|G҅J!/4)u璪Y*ݪi<YsY _~ 96 &}%#pr8+{u7mB&dSC"uQ.jngqV3"],f^{a( "OD7a皦4uB Vt6ڳ!@KIh[+z %i~sP g ]s*2f0瘎<`4ΘL_ylkN,Tb*Go%%/_`6X\Ov3z b<qb"kP?}I޹dhRjI,\ ۭeHp p#bU9IyL`뾢K'GTX=o 8𵭍o3}<-)`9$_PFqY}6Ɖ"2I'>i;jҵ Kd u M‰JeK 38!"0FDz hچs$r/z̗UAE$%[4]ۧvOmͱ R13HB[(N. 5B 7a6 o MeudM ciB"L"K# ʯUO! K&GıCuq;vލzGnco~.L{p ;#8ycrV4qSdLgbaG._^[~lOEDT2?$>{-Dz '`#ᙅm`:m в- O mQUVV}S9~ |ʊX'?OB &kCZ"$x8|pʸ 7A6!gCQ4}1uDfk^+<bKQ-e+gxxLya˥7Ed{+= :I&i=Q4aƊ;[2&io"}u+%vi!ࠅXzcH } 2$ߚtq pi^CZNO^$\A0Ss2!Ga?vdGv?բjJ4- cN;?Eط^[s;>!OLkw6D=#1k[}fؓjY6  )<.+!]*~LX_x-Amd/IUbSְmJPcV\U"o +C1gqA7 w]RU#,0 8a.+Պ -\o̹n SciU}qe _#XEhC Vza0«pfL\ ToI?v!"lâ*"Z3H,DDوvqCeL\ 6)Uh7ilb'J׊*6*UbKJMoЅ3G,LZule3QUe`DbB?:B 'V "L4o]Q%UR3䛈5BMi F*FN]-d2;C1"kjm>~1U}DB@DSx'(YS$L/a & 6b\Dn>yߧ\ޱQ"lX?C|>u3:-"+JB;v`DءUrko;uꑐÄN=y?E䣁D{Y:_av= ȶnirGz@F|9ǧHH$} I]B ∪Nµ[uҎ mY,E%gA@c&31I0č-EQ=]"-"Ņӣ6Q##HXM ֯B ;wZ"3G7[ES&FbZ-. (nȴ` bywN<J#N E=WhӼg]ptD#K %!9a7HDހ_ڰYe<q<j9Cgn]lMڠD-0hqLRD]G C a{E0_LIO7O{9q;xt%3fOF4eIȖȻiZA6|?0] HO5u%b3otw}?lQ6D$^y{ϪM4W!lKܨ\ FiGm0TЙ+ڪ+_{ԆCea$ʾVDs/ u,7ŮVDaiQԑs"wٞ #mB+jI9F'uW)UOl;ϘVWT̤ylRD˲kqU,y_Dza(S vlӂK:mν=ׁזw{FuRK"l^lιKL )uQ9kFKI¼,a;G)1nxHWsN#eM;jة! '!#ξojn?A(BH?/XpDԊd:݄~% iԟtݘEpmli~s9L'/ Q=H=G{kux20gx2>cKznL*  &%|gv㒪^jCb<].٭v :<.rU523ex.v!5țU2D6KC| d2O*G?H@IENDB`ukui-biometric-auth/images/FingerVein/07.png0000664000175000017500000000553015167732630017641 0ustar fengfengPNG  IHDRbb IDATxo?6\PS[IqDԊHyhg8%4Ne*G\E"WJ \vxZ4PVyNAh9@ #!{fFɜFQCB#R4+k%v"2*7Mտu$Ddȸ^CyY**]]U TÐ (03]YQ'W 568\LkAtQI# ƅ9FZQ96Dd 76Zz¥2o@qez@A] J-@G]#fN9rVT;ZG_^;LT)ɚ7$]5wDAUD,Z|#w|DLĒ)=p@=޵k;| @@*C)D> w,AZsy{n .< ~GZQIUESc4 Kv} 'e'%b# /l)d) |@)I 3U5m4:I"i<%o*QG!~A#WA[FLh0Yo&aӕ}8l&)">]aLjvtms`33SΎ|%5#CsBքyaPp0$+l#yʏ U#VD 0XeCyXfUy_DFkQ2HsgHĞD eODvN=t;':Gl=ctׁ:|!sFc8oGrչ׫GU&"_ wTum"?{z#)@⼪wk"< -W= 0CU}<pcy$"n|SD^HmNM3Kӗp8Ed%"Jm$@DfڇI ;tꑐI:ywݕX#&KsZ:aa9s6DdKUhJz@FR5pGdHA|D,v"dVv~MQ;Bf5K+6iG&31I0Y7;_5U."["r7ɶMTmD vڣ 6}CXNZd&u5eӔ!)⢹f){͋-ˑPF>AzFoH'=UvMCQPFt X-J 5-K`q=@m&?%QzEZ0olyr:8ڱo!n4I#ZVA}ŝ3Im%bj4փ"MuD`o&d7OkmDk,&<C1F4eIȦl-ZtA 5W]D fv "b1um% g{>!>'1Exc;6 $ZCDXsEs"HɂA\uJ;ZClV=\A֣5Db. #ck+ZE9$nnX!ytqb*" Q°(H*H5Ml{tcKOC0xЊVaμuxdSjv{cvvWTmCSDJySMoQ3$넷44Q4McZ|I͹:NzO5"I{[ !$֥M^IxnRxm\d' c' և ;㼳$%ӈ57ӎ0 ! '!#tjn/C_ !m$¿oXp DABZEDf:w{d !DTݜ1Ipm Nk9N^$X[l2&"rs+q/Rz bk$M3udzLoLɢ9*a>ġmzN?0;+3{ FoK'GWjǣb3;A/sߖv!2oDU2F+jG85WE9UBqIENDB`ukui-biometric-auth/images/FingerVein/06.png0000664000175000017500000000543315167732630017642 0ustar fengfengPNG  IHDRbb IDATx]nf;1'!K}'`߀70oyVq- 1 cW.LM{f7ϑ%ӷt΂ݖ)>!YqG~ ''NC$f^ky02b?ߙ `AHI#jk?pN#bYi"$|k2{8m9";BDHŸ2Ksx IDfskLi'MDl>\sGD>(O!7<Š'4KA~7]8'.K8Ӟ]#]6e?p_yGDg4.043TXI# 3_i֠y%1MސjՈDhI}%$>k2FhFaؤr`n<^\Tb?ag5pB&7pN˦e1%o"8HPwdgkं ̼`o%?"\Cg$ȘeYD%L3|EDۙDU:pHGI!dWy Y8r9mDX$7 Y;/**"舣Y8?곾A*DI9%16U.,0 BD4B33/ZV:\QF7od+<3sГ2S̼[Ee%j q{'U$'@0| BLw3-\PA 36/\[w."nрbϞW8=z%f޶Sh+oED\ ҕ]WyK8@(&B ݌ 6\͟p\8`n ~q[ 1SD `#^8 @D{Zk{[,mm}y׳kZ$ӥ e*,v#5.Z]Q5g}27Cྥטo4M״K.νk%X6"z{[dž yI7iBJ}n8g D\77o= R{[^]DR-\FxH[5`qZC泯IC#Ԯn#Nx 3fh!!A[/!Z]  B'_A\}xx gΚH 7'cmXh#(82ZV%~4S3y) L@Nedײ%βJȻU]κ6dWe _Ɂ~wȣUr+2{\k9Kq \ck^NUJ~p"s-EjlIENDB`ukui-biometric-auth/images/FingerVein/12.png0000664000175000017500000000545415167732630017642 0ustar fengfengPNG  IHDRbb IDATxoG?c;v9U6rQVXD7QxqUZxppyEB ]P\Z @Z IĮӇ9swvޛcMhv=9gf5xs&:aj95z4liMc̻_c>$N.w9Y53HTƢ6nKeuż+-j:笉m@KޅbEd{qEUpF]K"-ꎖ9:oѫEDdEwV Х Ez]ʹ6eVNuZk^S>?Jxqhh+J+ֆm"r7TZ*v hV&BIo>L9(FF!DdPHIʡ1t" 2"Ϳt$8d\By#BOk1-= D쐱^n;Z1L"ֽ*$l$qXXN|")m/4a[Ca B3FTNDp*bћD4$|r7 I8nSߠ#ȏbu9I,w`(9IwC}Iz J#!dy*c^hw ED] m$+=1ʈESfdzz1coD^r{( w"Ć0j9^j!L"7Q[eeG)?5o;o"tM\0@J~=lҡco;XȥƘD->bß;uhG "XR6w+b}4'n|-D]-b _c],c ,豰a e Hƴ$YUj/IsaXF#cXś4v3Wvؕcud=yj}ȢD4C EV"oT7YQE"sDCм_4TDrÞJ1J">jEW /T?W/yrD=#Bmb_.mʮ*ɓվ_,QVZ[0w?#"}Ȑ- ;"Go.֏4^w@C"^HzrGB:%[yLnK=ޑV Yqd?DH2*JkVfZQCc] "TiP>:~@'{IZwG-~Y_%hj:>Jѐ "rp)=v^Z3Z 9k. wI[ChiAQ~.)1!"Ƙ"B`=zR}GZikq)$z?)"ڹ4љ?}axRDAI'Q|"z<~Uԟ:BB,֥m1ZpustV~p{4 {^yG=`5&RH: lN>ܥ]o4Hs:ܧBEp}q, 訧 TiiGO#tx6݋`[ C= GONs,4Tn >?Lc^[Kh9azV@N(?qCvu K>vf-גwJ!-~ we$*s8`q? OO/ l cv?evY/}hYbt7t/OƘ{{$Fz~ۯ%鏞`ˍP{*T!"$]c̞1枺$UǁȬ+RA>Ps^pDQV"vݤ`9/u5yADktG$K"r4DOvsAw4]U:JC1>6pV]A:6Tz'e]3D= sq}خ]P8%N°[$#DukG#BG*JIܛ@'55ҘZ agR~qP4V< aۀ^$Y),-"t3!R&h5Rǁ/kpo:ANz$ ;#CH)yi"=w} $*8g hi;[&17Edl-<[ؠ ?oힴf&r;}JR:"H H=D"DS,r&N )ujN!{ t N;BOD;c`%'3x dȧ,:#QPs=kS #~u u7H>z1u.35rNc?/1PvȺ u]wS?X.Rlc~؉e$_H[CoHZ+YG4 B&cXSGjEP㚫ؗp>83CY _IENDB`ukui-biometric-auth/images/FingerVein/04.png0000664000175000017500000000552215167732630017637 0ustar fengfengPNG  IHDRbb IDATxOlIe;qlbR,G6DD*(Qs$N R,YqB8 $\@ VDDIHH+V8wz5=RuTWWޫWU9`lnƴCAD_ʵz|9˵ |'c_;&exYNjB*>9t+{T|Ņ8f p_kqiT{IkUkM(E $[5TH/P_xo&GyN%TȨji Q[Y)  "2&""rHDȤ)MҴz!q2J7f.Xox ?2 `3q8vܙs[؆7&a/!@v}y BD&~>nXBb$#;5MgOsbIDD! I^'$v~CBw)wg5o>97z = joom}#zņ$Bi>6Ykw%%"ED?l¡>"n5bHcքqIkG`3??~ :Uk_ص" :v4K1zBx `8aI!=s{@IZcY68k="[2l 3yᵞְ#"cz0TPǁx9Lk|D-A;͗% ڋ8Is̓F ’ck"p놄W&!ۉ%0v9I 2R[}xI=a= qZ&-/ ۢYݲ:26s o8F:px-v}T='"2{eqFAXxZDqR,a`M5"bF"=WR"s,DV("bJT9#t|s TTCp"l;*-h<]pY*դl EaFa($0Ў ܮ?+4IDgpNA=œV"lEL(2DLM&Ɔ&4%f%gXoiѨc: loI694(^;&5?9֨m#bHj!nƎ={=6"9網^dii +D̊x\z~IQ91iPYR]Bhwkd&AqG|XT9^Cpp&2"%=! f* hbׄtȨEjW#oG΋JLSp/c y"-e^4W4"Lt3| ZyPFtXJ 5-gՒss^a'K"7a7 &i3G1h$g2L.i:T"qYHhn<''./G 6t?bEL]7~pâ1npkA$z[|v9MQж 4ι]ܖ "\"^mxfP\xh*;Ip{o͖D :l%CD~6\}QD>Fs"0@%F>\J;C„|Z\Aƣ1D(B.3#fk*E: n!-mJkm5EAfEX' %.Yih k?ZH"ԙN 1!G=uaiuEʿn/PԹ{TD.\&G 5Mox_;;p xc#} iz[ !$B祻&靻SB7W&YC[ o-[Wj?DÆp5G4"lÌC2>& i vS{p{ b VD"+T -$QDî$._AWv?֝4W@fde>.OZ cܝ~x ^ 9wȲeoG%7g oɲTнPY/cjG?jPkDh \՟>P X5,2>0ϥrs?ƫ!(r,qu`Ye'@1lIENDB`ukui-biometric-auth/images/FingerVein/02.png0000664000175000017500000000535715167732630017643 0ustar fengfengPNG  IHDRbb IDATxn7flhWJ7Xr>AoHy\D"m0ʐ11cN.tMg<]JU=WT9U5BU|f `bȳli, V\~f=g `v#-p>2rd@艈-zA9ݳ.pWD/TL JSc2pfg{',aoqd?7/{m`KDJUg@4eg3#W/F\!(jX~G8.|H<]ța7V_4:JD}x]D ribO_q{L{#ěy8o G_HHx"r%@*<6OZ3 gE`+$/6[>PG$' /ߒ ;vq$@Mt#k ?_Z}^7(~U}SO0؈zBΘ9UR0-}B@&I8$A I~ȠۍP}G&\ l*U4\NU`ϱ*%"*|'0>$y*Ţ}TEF-Dd\D˾oʏI*#?֖u4 [`];lUu6'SE%D ]f*=Rd,TH1adpQ:Db{;1lẠ֠*4= Foa -$&i.$}ul([#}MÓ\VFuW ig,F^TZ1Mq^ꇪzᳯp-=#"?JچY\au * k+|j/4Yiiہܳʁo2Oe OUѯO0OlW)i9IQ>{HZ3.Nbԉ0=s*R--C#B150T9@NL]+ "e ;=a|YjWCH0sbiWӊȡӠ6L"zO3oVp䤻}lRZADqmODKUm":kh FL#'pԓ lC:8PۛT-û[UIx4"BX6B,sjGӈr`dXqQ&ED粌^KPټwG#ܪ=DxQ4M$%&ớux`KC8h"M<h"ѧ4M$"ĩ95KԘF82pNU#Eપ^|'9cFvQէ Dj= ,${Uh[D䱪n̟7p!ұ 0pwD0ӟжV'yA.sb̉ vuel9A`p6ZU<~sXUՁ b!Df JDmr@ 瓚ř}Ӫ50$/m}[ǷNcΕ z/2|6_oD/fGĢۚ!ṵ5gIj{[CB̨e`a۱BҨ{BuHUD/0EFDj̼$DA#U= Ѫ/T> ?m\wFHℾ|@7EgXQٴpaLQ9)p ,j<)K]8!&d&0 м7f*?*U."G"%8=_rU}9 ! w.(EfWf4H 8o.YZ#т̋x%*qhBm>FZ0/W^ydyc$4Y^EjhyDF &Vu% @/Y8+C><Ђ E&n\DG w?d5sKabѸfn$;_Iǣwik |#Cp55WMDTD0 /xcZfe V"YQ8s=Ƶ flRj坛c~h!dI\8\ǙFiG4Dt֊! Gh0ڇ. #eQaν.^c0x!.niQHIOu!,CtDBЊ(0g^eZ_o~taשivEh 'VbxZQUĊOE$ 35CqZΗt՜{7ҧazjKM2<8!S]^5bYC[˸l9ɢD}N#RHk8!pMҐ`m{/EH j!1nNXu{@B""N/B Cئ #$~"3j!ε%oQ B:|g:& o[D1#xy0g6-7|c_,cxN@+;Tkz°wn0YoW3fGoUV[M?hv m0'q+κ~O {vr5ȗ8U;3~vl86']`df$ IENDB`ukui-biometric-auth/images/FingerVein/01.png0000664000175000017500000000475415167732630017642 0ustar fengfengPNG  IHDRbb IDATxj% / !#acg.$y C5r%3_Hp?O_D~oBUo۶4/q{c.x$"#BU?ڗ'STDT/;mhmmr|oAUÑL<ľ<_ {f+@Ucg-`cqE|~/ UwI$#K1{8Ur_8O> 7?@}#"lv+}La$Sǵ!sG9p*""?7d1Ш0uO&!CQ-\7Mٟ&??7pG˦h)$-ڵD $B\]pF3IBv<4%w&I02۳ =:t %uTS) ozT4!:"s% 8 Q0WIm@D`7TĖ_G@+>%&xU*ICc`쭨RӅ9Ahm,m%ꎪ~w=VE}ߞjq5mAtaީXasj?(ԒyK|(Wh~~ۊb׮schD0I:t5J9zZ&~>iV#1g\!,l j'ԆuGZ ڌᕍ!ڨM" EΦ 'jD:4EsKdTS0$I۸9dbLsTL"FT'&LdԬ387|m&b؞ U*bd`1rRq ?$a s[Uu ' TZ7me!dUm\ږWca fݖBဿ1\)YyvcDY.=_X}kbt۴6*HG~EE"Dh"RAXIt񽄥sH&C2Sȹ$VF5u1EESDL oT~NyC%"]-`UKH;Bzلu<ת2>?H+-` D03Nq譪V'P3b v}ehl9A`2{"bvTuA*xti%",9`Zǩ ஭}=IazlE _U."/l/ |md0Fs8"Tmh"y¹clR|Խ{U=m^Sֈ! f M sDZUdRuU}AV+jRU"r$)'鲙y8"Uu=?*%h C\9WeՒGB :)IG&S1I0 TBT\DE3YUTvr\Q JV.jBVq.L^MhD5HJ^qaEʲ,^ #)%ڼԢyg=~ӪIZHyIP5W㢨mC{LI"Ƭ fyi*se>qoS[$#t6zj`&WIKBD0kTGD%|gBC .ĚHXo~d<(Z_ (qK:x炘Gi~G "Eּ P]uI4_.ǴѪf1*WӢp{ŠfV/J & I}Qu;UEu dKB6N]uJ:!|P>W`rq|H}4rjff_Hs/xi "qsҲHK2K3m!(2˳P_HED3h u*EZxN];>ccc6Wa*VEn8_s,̞W1`ۺ2$IťiLƮ_Z7c֐YKj:.nej{d :͑D=$!.jn!aSHDX!LX.t{AB""/B 3ml)8I|]Ksm\1i޼XBt | 8Gmt& [y1#xyYg_k‘mvRdz7r~̟OlHUhCakzP6eX5ӣ샧zd qN Nc}87x88ξ~Wvĸ=[M"NT-y٘?ѹ&LIENDB`ukui-biometric-auth/images/FingerVein/13.png0000664000175000017500000000532515167732630017640 0ustar fengfengPNG  IHDRbb IDATx]o\WDZK ((@qB">l mpݱybUňHlUQC'rIjɯ{޼7s']z~%+b7  $/XD%uz#", z&"A^kArU[$'MXՂZe#[7?nWC ]0c*(]Z&ZSޮoQ ̼K2CukԾ3o#[5\ }بIk9WNgcHZ))V_L劅X0xG+u6a[U}ᥨA[RV"ު@:WM|L y.ȨjʉЦ$x[GG[WLoL+ͭb!tCZ>@ў;ZQ%&CM'" tUE }+ o":L6xdjE 3z'qzH@G? tZ9&@*ӝRd鎿sQ LHyvr8 AH#^Q;#}7/|^DЙ01{+%F0ĨĄ&"j,vcdCQg#2ӮFtt1VVu Ad"NDxh} L4;ptv1|/"m75.D][0BܢM;M1HƬdUuTk:߄-5iytKZh#mmXٛvV|U5BD>0v;A\N>4GL-HDPF"vN!BDxa戆6khh#S6oV1Mh#Ku  m$:u #"3.j}_:"]s K$/50Vv@Pewqɗ ]D ؀l4k~qsO^LoϪ #o8xJY$U# AF^wO(v5dpRN"Lgfz}D o8,!?DҮѵY[<뚉{Ԟ%į3}*R1r*=/]a>f*`Z}dCln_BWztxpw([2ԈBo\8*"rH,pxL;18׎oJMM}S` _D.^Q7--DX^-Ո5A/BMJdjǰ&M8$+dY3t(KB}'$"{pgڏ,p WNwn*[,". H `@ABX2t58Y2n\߾HFx o޿m I '$㜫w"$T"*$4dID#௿30c{Oؼ?Hxw5}%ÒWK~ax lʒ?pG(doG,S"򸄚Fb,"H qI|O"F6! OjYIG"2Q)ESH>g% rD #4?6q\]@nϑ_$ k~)>{4 >-h#GyA,Wp A7l d#! N5k9C}_;$ Wk+ۑgk%Œiwx_< Ink(}9}!!!/qgֆ &13a'#KoO̱g䟳D2\Ax {PャHv81H^pD% Q>MU]ò2Wz2D\V㮈|Z "Huw 91]ۏDNȸ*nHك)}b^{$j&C6)"A'k=i$C^gQr|&"h:+G'njcOVQD(I~VI*D]uAv?t}^SmSQ+I! tAgڦԣbd{@#E}z^2q ړL M&D7qx7imQy4v%;$mD Ƙ*BIzy}EzR60Hȷ̊pW%Ar!id8s0l{ԏG"-B-! sH[T cHnm2@PY%ߕ2Ck5T\ m9m)YndWn5 Q"׆tcNIyX*bU 0RJ;5aUk5pR Tܫ2#mP mWMxﭙ(Q $R/eq]Y)!$8dTAVƑ"aUGÐiߘ*j`D#mT(Uq>aIQt d}UEֆ T+iCJ+B 0|`<|^IWt8@]-fqhPeS#Uq0YWbr H! )9o m3ʿ9.4ED$ p,~"PD: UƘU_ ;CF}KiBh.1Z* $Dt7u& ^pwPB#] ʯX"1S#!칋3&D y KJ~[q^cH؋uq ][0<p1My:{2 R#BDz]q΄Ú4%TcXS7^>J$VJ#SK_a1ic"+ε!.&& ٩`"j'$K u2~04;?=@>$BrEU$H.\ 9OT%$pEW̧ܜ:._"%ao˳xPJ?ϸ:wny&#($I9ҤhB{ lw`{#,Ap ?P$ s'y\ [Q?}EФ _>m%%nO=!g\әEƘ3k &"BE8UˈX@>)xEojn!<sX dejpk$3cTS3|Q9MIJz55X"ޒwx DZ4Kw.Ͼ' &~Oϐ$L `U9#y1PC"H.!i*\!▕[J]⿍$YK Hy?C9\5O!k,`T #gg^K؂r&קgTpDKd5$ &c1.I.JMvZ1a_C5u_:aN¾"ioLri"D޻k2J?y"~=* ;6~ yM7/=QoHoo) 7|3ERo.Ipy~<$L&1o%$#;'ANii>-HY0>!'+N8 *uDȪ#8zY v,jKM=M}};DIsIENDB`ukui-biometric-auth/images/FingerVein/11.png0000664000175000017500000000550115167732630017632 0ustar fengfengPNG  IHDRbb IDATxoG?c;bܴiJL*_*((G\>!D-$o.R]ě vBK#b%$#9<̙7{nhgΜ9ߙ33gf<$0I6c޾ "3@H _2ƼX9匷/"pAZ3?r)U\I "6lƴV\@db\Bg,ش zhF  "%\Jfe 8LFrhKy,[=Y!"sz2W@/(jMz)|:[>=t{邅qXZje PtӮ8)JRVI7JVE$$ hy&S*EadBD Ki,‰PSPIRn* o#!Aƥ+/+H|47'ʫ"$!c)^ftٓ;XQ$ ^Jq{Da*/t ("P\_cmHv!*BD,K< 8_fD Druԕb$-HԢ\8$:AJ0"Q5oiE/>ARÒ?Sep7Cwcm,A*ADua447"9 \YME5&o"ʌy? /7e&1 Yݍ1巈,"1h䑦D8.&)Dc%,);!a>=>}n81AfEk(t0W׀)cV)-O5灥8$CX"U/R3ag&֧7j9wصjƘ<~ 獺{u$j(SQG"QyD8:2PG"$HĊv&b/Dh-@^#YyvD$z^_+jGbыž\/u0n-wwmc-".ឆ`ȅpȻ$Å i.Y#I14o: UW.qa2"sOFpmGG$}7>V+爈+dH^L}l ~ 40pH𨈸[ƘNʂa"z'v ྊI7 l_XD>|Konցb[}G%{8 [^~q-1}1 "F 懡D|FS菽&YF:OuI~?<{X^T~ F*{ hyiҖwDOs1w-™qTqkrbbk!x7_&N$)'5aÞOhi'',irm;RV%,> >'MU&&Qk-vN|]%Χu U$ُ5B\SE$.MB״ɖ~6pxRG 6U;^:֔k|%-d%I+@XaySs$\1lfH,{hsfY+](KfD$xQ& YVVTnNr3cV =nS\Ƙ=>ZC+KV䈻:踾hTraH+GVGL҆1T $;rSEwCC3IU%RbPǢ;-#B_OIpJfƘ;XMc̍bU|c7KW'fOjqhADZ^7lccf+#*Epݿf29iU%&c̎~9] Կ%"'uXKTD'Տ\=#"'h*C y\=5Wj!B}Pzz,k` VyTGeńZ}ks}qJpJܿYQE"nQԶ;7k<*G·VQI"ԙ:a=Z׉ǁJ~qPco4uhz4ww4N4Mv;ǀOsou%Ν$nDlB*IK; Df!":f hɽ0]F1"rI wsTE$6{3mAr=YR9" 7`#6K/Պ*6MlXަTĺulM!w !'"$la]-B6ʜѷeCws9mS #s%OYsBSCDf{Yz9!]4/v } U'[ezڐW,_in`6?#^0s\D\{\w ǿڣ&c̏Mb2#՚3GFQIENDB`ukui-biometric-auth/images/FingerVein/15.png0000664000175000017500000000540615167732630017642 0ustar fengfengPNG  IHDRbb IDATx]ϏGz#I%GyQ$ y.H!y/\8΁5W.q:q‼pl8ZG1^P_tvtq>=UWwE+b ;H^ D:S;#˵jwz -'~%Js*-ȦajFZUU ]0a*8 - &P.goєK̬s2Cu%j_\1Y.l4$Е E\W*g#'))PL򥚅X2x 4G˥5KK>R4 Wթf dHPWޚ)!ŌLQAB#RԕQ;j ZIGMeD:<2n_}D0kߊW`5vSULhk26ҁ*5#wN"M6L8lG'>AbZ[/"J&[+L >FR + A1>$b8 U&q4{P08@]#fIhPgS#Eq0]bz J&(9o 2v%i^w3''î/Wf!h|q"+jw[% "_۳U[>-Q2AD a2"+ |Zz0LDS5QseWMG H,T ]SYҭX[XD @"1 @rTۊ1a>j^Vw]Ckc"V5*=7e}S=EÛv2 D.Uթ\‡ [3iyD OGێaM5ޤcWke&;U"D)hFꈙE54)D" kRE"<戆.&D$HĞ=w&bE",zM PH7%DDU]sD(vcmtUv_o7WK FfgK[ap /n m{2Y5D#෋=Lepya9 !_j1R0Py,!c [ {A.7h ٦;&&әBfüDW6 V/+t9T6_WLk-|,t9~S rSw*UD$kmdClf]BAk<;sDGeL&%FFe*3ED c'؏ccvCшuC = Fe{^Mp3=V׋Q$7'](2}I3L36M]U?+="6ʒO>uC'$"ɇpgڏ,p W! ԶYD~Uz{Ys'f[wՆ,4AKeMh4MmjfηA[n}h֋th˞1ibzrg4kf_4tbcty_DpDV59f(^qD7p%bSp p LY"|06Gɤ*DTI`zxpw(/ifgq9DRΙm  _/\':$I$yigԽD%G~ GoO?)Pw 7g: Wq@LC 3_EWHD&uOE"Js^$xy~੺h'xw5}aI  HD$ 8BB{~ys"򼜦11$,"!O!!Ɠ 9/o! KEi"YʷW<x~ "ϊ. J+|8K)ɫ%*HJpD|ɖ<4 &S;$}0Ousq~F"ƒO}Db'li(JPC*)&ʕ2"ܗ{]ˉ/Ùp**qo4Qm\:& GnH@ۄr~OƳ,,1''w>;<\ۦ$~a-#ߜv3W֑{A:/2n ;ŠD5m4OiC} = oj Sm$Gp*yU]WQ׳B[e) o|G'33IH׈x)BZI+=[,+BBRsIKnh| EG>$7iǪ)Dh>ԡϑ "ϴsC7ݙ:"Npd9NF"Kyb7\ י!"B[?|?z91+ n?^H3d^y琜}oB U޿E䓬}Uo^(JY+B_;sH3^~uc<'g#u;dDz&!")FLu_ooΩ6Y>ܘǽ609!mSHn.20\ 2tP1ކg [Mǭw1eT;܂T?Wu+IENDB`ukui-biometric-auth/images/FingerVein/18.png0000664000175000017500000000516215167732630017644 0ustar fengfengPNG  IHDRbb 9IDATx]MhdYn:Ɍ08B \3E{SRDq 'DوAg"Ղ QJ*{%I[[UޫT= A9 1J $C88#?5=r%Ccy^ArM$/I#-t: mPx" ۑ4X}?)!; m+'G.+DV)]ר s=ffoGe $0h(Asu!8AA\⩘V{5'b]%a,8Z)xw9Ž$|å^fZkR"B׆ 󂶏VD'DjW+b O3|a 0> 0BQG@j5uƻ0RdY_kٹ(`%FH缁t"O \Os'é f)H\I8bu:Wc7C[./Q Ap"h0zUKib]bBT;J1D84l`5tPzb] oXcS5 F "bsfL6D3 y Ka[qAcBMq{D][Pd06B-|;Ճ]4<pږɘ5"6NΔj s*lV90&@5?!l=x]WcwFc G hCk6biE"&C M&"4HkLDht&9D_4tD8s7u]DX&t^ .#›ۊ!M#%cmtv"C=mg2:!`(v<3c߶# ''0xpD;S68}:s@}"_1e]< –o^!a%¥J!'T"@}3`: tw7oY47}Z ^c̪*}NׂJ{Ea)z_ZJHD0[r5nߧ Vܱ͵%`ŻkKG'X}T\ndZ#Jmddv]psX*"rH8~)avm%bO')<Dڲ'q,31s hƛ>Dc>0ƼpH,R#<{|gLM}u~`yF ՛ 5لG'rGLC"fy`vxpw(7B5Iuv"S̶ {eՌ1^ǽD[pgi11]˱;t2 jE^1#y7z:"V$h%2t&RRZIՊ~`EZ)8NidD45 ^s"Ffd;u \D@k^O CxV!$=Uk}Bnxm4֞`v==SyW袈i[G+nC :-4"vTzz'%11k$oCKJ?%)^S $Dzws+U s e\_ _o>I^x.չ+c̋@Y. $C/"ġ#'e'~ ` ?#\?% j|\{WpĪUضy" ` k; M& -$ / ϽP!`߁WsZ*ɕ5'h$o#Uy5&:yn<" 9 $gƘee[v`'avf$y o+xE}*"f i S[< {d#H ޿DKW+?b{.1_!hyZ&+qO%7(yP$(Z╃v{Sg=qt7TW:U#8is5`ܱguCs,|GDVqV_~ yeKyVKz]Ul%he>v9M슻y }B|KVax`qk@-|`n꥚b]7#*Qf^͏5Q*G:E=+*-t'{͚ +HŕR#ݭ®OuRPIݻC&|> NO 7Lmm"'S{b/7y+wmUE; SDN |ƹC OT"k!yj-[Afo m5ljzAQ2!6s9O,5 0'#m? $;%@v~tρ7K_WIp" 533Gœ#cy]n֓')VaC[!SOJ Z8RN2I5#".Mo±;@%s]TDVKL'"t HAAئcj(#cƅ7/KNolyJp{G).hdCU΅Ө""iED#P<5@3ܙZ61wDĹD:F"pt{Oh#m$7P#uL PHǁ9$q`TSL98shwj"Z"̼1So|YEgv[Q'cFbKؒM7E䑪>atxXt.%% ^a'ΨWXUW wU3頍 "bgZlEakOs3'/6,OP"6t6gRSBF"My"ҳX-zPg͝uqk' 1Dذ4 ~{b^SYB|Ip:af 2b;uꑐN=yE_DFMN;6M'#b$QMV\UȈsN~uxAyIݙF ☪NµMj'"!a70Z[mR똨TLa wMG 5ȎCqzf*jbD gr$Gߐ<R:K_/LjJH ָ.ZZ k#[bR-".t -e4r7zCQ0aV`( &8xV03w} јبIDHl [Ej=nly4r:8ڳo!nTI#FA{["JĂ ŜjoԈ3qqD`o&[kqFFQYq3WK N}lmdNS/l MCU("o v "b`1ϵM%b+o t}B<'ΨmJ4 !;vUcpNPW' U1D *.,o<C!vq0u5pg_S("̸'qIcFaB=Ңh"kd#Dys6&VȣU o6>̪zENJKgQUs&^fꏿCnWb:Qi^nQr`<37eqH#0UIENDB`ukui-biometric-auth/images/FingerVein/08.png0000664000175000017500000000554115167732630017644 0ustar fengfengPNG  IHDRbb (IDATx]n>` bbk U"PK"ܮ߀ < 70oxDxHQPM@ ,EWi3=^>3sf3f`Q,џ*{(0U#+׼X+rJDE.2?V}E{ѓxV\b|_lMih˹v-6?ޗB])e5.$+>3ln7 whgDE-_[:Cu5y&fF) 0,T/ ZE|K O2ʞ3Up!Θ(֤Gk-o6|U -E xʥ&A ɿi"G35sQ4FF+DJTFh1I( #lɑx@~YݘyGsK?q!!221k&o*Ԋ0~|U&~ /4\`7Ljщ*9mPxZÍ>$b'YuIAݎ~0sԵb85ᵢ k}q~ J#(5o [2VbMGA,"$^-\ ?V@iVA_G,"TP#"zcNφJ.QAp"ع04Ձe#ibhm1*+%D̛D(4M@A L!=Yۍon D8 CiE {i.hm90*)+; D0Cre^V_<<1QVEk,uHDOm`5dLUdsZo$ g4(V Ya$:swu$5&yaf>b/{hx} XuF`q/Xɜ9 m&I`{̼' b " U窈J3V+r_"ckb }E>3Bm04Né)>St)>4&'1Sמya(""sx'B_90~vH e8QlEO[p  =\ht[|h2 2fw#=D^\u" Lj{ND/B5hǜn 3AC4BS0'<0sM(FWrޓ,3?EDU:}>ho6m]$bFD􄙟-.9s̼ יW`pCDXQ_k3o _xQ悐4g $QΙ"t%.8/h HPD#.ܬvδ\dOjY[#@4bMPmAZ9=dsp-_}aͽH৐QSEFH n`#mmG ӄIo.Ȏ\#UkKuA(6z_-An2GMDg8Uw2FjGpgX/WIENDB`ukui-biometric-auth/images/FingerVein/09.png0000664000175000017500000000543015167732630017642 0ustar fengfengPNG  IHDRbb IDATx]n66xq`kbeE}EN^ < 70o`xor 2( #;\tՙxgzǛOj{ *E G9#?{,0 7'JU9_#kJF_}YVK||V\e̼̯)q[Z\lK~bw͏з.tɊݖ2a]⬰k@Kr`0v+~w폊 xNEߩ8^w8_^KB֭|MYnb}!R/jg9'X9Q )b]ZqV*&li`Zoh)Z(CU.5)6[hNM!$}4SFʌ)Ky)[a>5E""F(~iX!5"4֐Nj*AMM8Amtk, L޵cwJ#1fF.1r5YE"tkuD(psCXc`rp2)#=g>QTAD0I/L&s ;&?V7G?AQÐ>XRJ3p%H@1C{Cs"8`ɰiIv̛I oE3OAeaXD0i$""N̖b[p4Y·Gg|z@DciL%"yMD6|Ds -W ? M53q< }S@"3N0nd !Hg&KZӺx#-|MX2@Nޙt[ a W-Sr!a֐1kРCJ1b=z$ 1[EHH#!C94. |HqOW5XHց5\".@ ڼuS"i{ss"ڒ8D1F5! ]yɨld7O*9a6F8(f#"t$6'р_{ ̼ADz3]%UhW&cSpy?p NԿ5Q!v{VcېVND\˟pmE4DHEZC"-HjYfv#me"d^[lA$i;#ԕ$=%ؕX !o\iRwҚ͌gF fCUodpᆻ?>#aNpv;%[pDrq"<<.j2,kv,bҎFJĔ&A ǡpK`ҜƂ"zH0SM}\,CB}С墸1Cdݗ˯'Ď~%7lpߞބ:ӹRd E*#N*M: qhկị̌QNUA>}}9h$+IENDB`ukui-biometric-auth/images/FingerVein/10.png0000664000175000017500000000555415167732630017641 0ustar fengfengPNG  IHDRbb 3IDATxKGg㉝ؙ0V"_AlmE b1orf!X|1EX#@D{JwDi΄ѱ҈0.9Qf="l1eU;J1ᲉS5A` e`! S~KB)e;SF!bC4?->&.HYY\ID 'VEt!s{HllQĚ : "k v/;NupOM1HLr:ժm\9TwKKZ4؟vhڒlWFYyݪ!"~7֛[ylmضh#}SC(m$Oa;ul:F"̯ m$b[D\cDl' PHDhěeD긹 UT)U l^PisS&qUmd=CTjkRq`a %>cׇ_~\4p]9}?H6/"oD:D%BUwY##K%_v/{x 'F xTUVk8* J!BU')`"&N Bޱ}xo^>< |L_fy!p ؋S]{U>DaQa$"lŸ \HĎYO b&Iz Q/Gw߳<>|t/~ o+8ւ8;v>k@WDB 0:MZtc á{g ~bn;,= "SGp E) =BWK$`$bqk9_Ue~<̚ `Sg{AwGؙ͢$PF:hvea[p5GBܕE#m z21h$$ 80toJh*AxYOIcjw8"L~ GDVqVY__ j< dz[#Aժ Z&#l,mYU;6 bj#Ep-|`jǛ <,{DS蚺I tqc==ǘ"h Azu1U}1D3h TWOUzGc0Й-ڪ+Hi<C~02-{~77,4qa(" ^aZZM$&L}"voƞiG0:W43W`?{ԛ5)5?ᕑpCzdzw6swC^TM7'gqo %$mDnBIKM޻>zB>U!-pqܾ UU;1Kb$ܣ7hiJY蛿ghSidžZe 7ZEH˲?j6BBEDf:#$o!'"{&L]?h":Wye>Fu& 4A e$̛4FlSm<`!e<9˘>aq ]>fz5qBg븣3Aq_tx-#MxT,̩xL,s$"ʩM1ʇT[Ms Ǎ3 ɞIENDB`ukui-biometric-auth/images/FingerVein/14.png0000664000175000017500000000542015167732630017635 0ustar fengfengPNG  IHDRbb IDATxOh]Y?'MҴ:6AA]H  iHMw.܈D7*IfBqKNi-c$Nr{?==w0ŰꜻTPs<0G95[j6Ծ[t :usV^K2<tzΊȢQҦa,jA+;Ҷ l>_v flQ]u&-}`Ed߲1Ϊ0J~(ї)һF8gcOMZ#"+RS.꾦B􈫴xLھ%*NĬIH@WKqR^*l!"B !72rJAH:QC%!{3lNZ!v)Q9 IB@UeD82dܨ ꈐ}-f\e@ҽ}W5DHE]ZP@hפ;Z{Q%&CL I8G'>4]IQ QUDPXaXcDщdu! S+bLѕ8 ef@hG@-G??QWd ԭ2ޑ)EqH᯴%鵃(`"F$kސӶƾ(EDG aK 4!N8bp=4/yRJ'BƜFA 90MFS6QKe9c/:UX &Ȍ^/i,XwJIs+#LD!G "xR6(W*bC}쓫#"z^E{c"V5z5[5`9`Ae۩9U`)1kDllNjmTT<^=u@tHM:w4Ș]:vjs=BXol[:Q6HDՙF"戆6:&D%HVTv&bF",N@Yh#vSW"F,\_o+ZGb KJ]:"T}]%i/[::%`)Xmmm9 ]}g!mrY4nMdr淳r2aEz%#"0ިܗ>䅭~>"Bj=ޗ5d](`~>d93+}wkQWzc] 6* usV}o`^`3cK,[ zڀǧTn7ViƒI\ۗDU xbۖ/LKrHww^[2%2J]p%ѕ>XCB_ CǓ}q` nQ rU_{Oι_ʮgs3:vW^5bК~HP)&ݹdjG/n4 9 ͬq beP_Km(DT9wID/tA!iWCpu7mBvt@/W{0ZJqךz22䩦!˜D H+tS^5h*W.9?`զ&I/t%LAސ7>o颱KM(sEew׀"2fJD&E䈈41)TztKDG4`0Ot/o~7Ok|Բ=YC}>sUzi=D&BDNhGU?~ |Oπ?n҃ صv5wm}RI`>߲dXR,!ap$ B~ ~A~Ak#'!K@VL+ MLG"!qv)eImř#W*mP<ۧ5^e97 "B ic,39HT/bv'x`;bpmxB^S? xHgn;I1fs(L%-^i,߁/نݪ/*vೂ &`8aA yM}5cKjxNNK11|817,8xxCoUT?7HԓVQj^Sxϒ&+^>Gcy߳mgm;Fb÷)H:[uuO#~vWg˱g{PX^CT7+ A&AYm!n/"rx9!>[ιKLHsNa7q>IW:R%G6rAأqD(sQ+Isn$)3=U`R*G=O:úޅWF#2a}d|opk ojPud'OƱo,nǒci$杶H󼃟6ze-⻱G'iV3~^;n W#t]>0#PNk%[CN_Mg!#tpL{xB3~[EH8ι'{i%~qu4F >;qp!D%W;m>'Ed`!9*σG:c»{'oWgs_e$t1Ar5ە|C9: ӔƮaKJi*뎾^P=zU?J[Z{]Y. InH[OWS)Ab9#")AȗNo+#m^q.fPD#Ֆ3C /Q$_ϡIENDB`ukui-biometric-auth/man/0000775000175000017500000000000015167732644014161 5ustar fengfengukui-biometric-auth/man/uniauth-backend.10000664000175000017500000000133215167732644017304 0ustar fengfeng.\" Man Page for bioctl .TH BIOCTL 1 "August 05, 2018" .SH "NAME" bioctl \- control tool for biometric authentication .SH "SYNOPSIS" .B bioctl .SH "DESCRIPTION" .B bioctl is a control tool for biometric authentication in the UKUI desktop. It show or change the status that biometric authentication is enabled or not. .TP \fB status\fR Show the status of biometric authentication. .TP \fB enable\fR Enable biometric authentication. .TP \fB disable\fR Disable biometric authenticaion. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-biometric-auth/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: yanghao (2018) ukui-biometric-auth/man/bioauth.10000664000175000017500000000121415167732630015667 0ustar fengfeng.\" Man Page for bioauth .TH BIOCTL 1 "August 05, 2018" .SH "NAME" bioauth \- command line binary for biometric authentication .SH "SYNOPSIS" .B bioauth .SH "DESCRIPTION" .B bioauth is a command line tool for biometric authentication in the UKUI desktop. It authenticate user by verify biometric features. .TP \fB --user\fR The user to be anthenticated. .TP \fB --device\fR The device for authentication. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-biometric-auth/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: yanghao (2018) ukui-biometric-auth/man/biorestart.10000664000175000017500000000133215167732644016420 0ustar fengfeng.\" Man Page for bioctl .TH BIOCTL 1 "August 05, 2018" .SH "NAME" bioctl \- control tool for biometric authentication .SH "SYNOPSIS" .B bioctl .SH "DESCRIPTION" .B bioctl is a control tool for biometric authentication in the UKUI desktop. It show or change the status that biometric authentication is enabled or not. .TP \fB status\fR Show the status of biometric authentication. .TP \fB enable\fR Enable biometric authentication. .TP \fB disable\fR Disable biometric authenticaion. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-biometric-auth/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: yanghao (2018) ukui-biometric-auth/man/biodrvctl.10000664000175000017500000000120215167732630016221 0ustar fengfeng.\" Man Page for bioctl .TH BIOCTL 1 "August 05, 2018" .SH "NAME" bioctl \- control tool for biometric device driver .SH "SYNOPSIS" .B biodrvctl .SH "DESCRIPTION" .B biodrvctl is a control tool for biometric device driver in the UKUI desktop. It changes the status of biometric device driver. .TP \fB enable\fR Enable biometric device driver. .TP \fB disable\fR Disable biometric device driver. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-biometric-auth/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: yanghao (2018) ukui-biometric-auth/man/bioctl.10000664000175000017500000000133215167732630015511 0ustar fengfeng.\" Man Page for bioctl .TH BIOCTL 1 "August 05, 2018" .SH "NAME" bioctl \- control tool for biometric authentication .SH "SYNOPSIS" .B bioctl .SH "DESCRIPTION" .B bioctl is a control tool for biometric authentication in the UKUI desktop. It show or change the status that biometric authentication is enabled or not. .TP \fB status\fR Show the status of biometric authentication. .TP \fB enable\fR Enable biometric authentication. .TP \fB disable\fR Disable biometric authenticaion. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-biometric-auth/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: yanghao (2018) ukui-biometric-auth/man/bioctl-helper.10000664000175000017500000000133215167732644016773 0ustar fengfeng.\" Man Page for bioctl .TH BIOCTL 1 "August 05, 2018" .SH "NAME" bioctl \- control tool for biometric authentication .SH "SYNOPSIS" .B bioctl .SH "DESCRIPTION" .B bioctl is a control tool for biometric authentication in the UKUI desktop. It show or change the status that biometric authentication is enabled or not. .TP \fB status\fR Show the status of biometric authentication. .TP \fB enable\fR Enable biometric authentication. .TP \fB disable\fR Disable biometric authenticaion. .SH "BUGS" .SS Should you encounter any bugs, they may be reported at: http://github.com/ukui/ukui-biometric-auth/issues .SH "AUTHORS" .SS This Manual Page has been written for the UKUI Desktop Environment by: yanghao (2018) ukui-biometric-auth/CMakeLists.txt0000664000175000017500000000361615167732644016154 0ustar fengfengcmake_minimum_required(VERSION 3.16) project(ukui-biometric-auth) # 尝试查找Qt6,如果失败则回退到Qt5 find_package(Qt6 COMPONENTS Core Widgets DBus Svg QUIET) if(Qt6_FOUND) message(STATUS "Using Qt6") set(QT_VERSION_MAJOR 6) find_package(Qt6LinguistTools REQUIRED) set(QT_PREFIX Qt6) set(QT_LINGUIST_TOOLS_CMAKE_PACKAGE_NAME Qt6LinguistTools) else() message(STATUS "Qt6 not found, trying Qt5") find_package(Qt5 COMPONENTS Core Widgets DBus Svg REQUIRED) find_package(Qt5LinguistTools REQUIRED) set(QT_VERSION_MAJOR 5) set(QT_PREFIX Qt5) set(QT_LINGUIST_TOOLS_CMAKE_PACKAGE_NAME Qt5LinguistTools) endif() # 设置Qt版本相关的定义 add_definitions(-DQT_VERSION_MAJOR=${QT_VERSION_MAJOR}) # 输出版本信息 message(STATUS "Qt版本: ${QT_VERSION_MAJOR}") message(STATUS "Qt前缀: ${QT_PREFIX}") message(STATUS "C++标准: ${CMAKE_CXX_STANDARD}") find_package(OpenCV REQUIRED) find_package(PkgConfig) pkg_check_modules(GIOUNIX2 REQUIRED gio-unix-2.0) pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0) set(UKUI_BIOMETRIC_DIR /usr/share/ukui-biometric) set(CMAKE_INSTALL_PREFIX /usr) #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror") set(CMAKE_INCLUDE_CURRENT_DIR ON) # 根据Qt版本设置C++标准 if(QT_VERSION_MAJOR EQUAL 6) set(CMAKE_CXX_STANDARD 17) else() set(CMAKE_CXX_STANDARD 11) endif() set (CONDOR_SCRIPT_PERMS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) add_compile_options(-fPIC) add_definitions(-DUKUI_BIOMETRIC=${UKUI_BIOMETRIC_DIR}) add_definitions(-DCONFIG_FILE=/etc/biometric-auth/ukui-biometric.conf) add_subdirectory(bioauth) add_subdirectory(bioauth-bin) add_subdirectory(pam-biometric) add_subdirectory(polkit-agent) add_subdirectory(uniauth-backend) add_subdirectory(images) add_dependencies(bioauth BioAuth) add_dependencies(polkit-ukui-authentication-agent-1 BioAuthWidgets) ukui-biometric-auth/COPYING0000664000175000017500000010451315167732644014445 0ustar fengfeng GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ukui-biometric-auth/uniauth-backend/0000775000175000017500000000000015167732644016450 5ustar fengfengukui-biometric-auth/uniauth-backend/src/0000775000175000017500000000000015167732644017237 5ustar fengfengukui-biometric-auth/uniauth-backend/src/servicemanager.cpp0000664000175000017500000000600515167732631022733 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "servicemanager.h" #include #include #define SERVICE "biometric-authentication.service" #define DBUS_SERVICE "org.ukui.Biometric" #define DBUS_PATH "/org/ukui/Biometric" #define DBUS_INTERFACE "org.ukui.Biometric" #define FD_DBUS_SERVICE "org.freedesktop.DBus" #define FD_DBUS_PATH "/org/freedesktop/DBus" #define FD_DBUS_INTERFACE "org.freedesktop.DBus" ServiceManager *ServiceManager::instance_ = nullptr; ServiceManager::ServiceManager(QObject *parent) : QObject(parent), dbusService(nullptr), bioService(nullptr) { init(); } void ServiceManager::init() { if(!dbusService) { dbusService = new QDBusInterface(FD_DBUS_SERVICE, FD_DBUS_PATH, FD_DBUS_INTERFACE, QDBusConnection::systemBus()); connect(dbusService, SIGNAL(NameOwnerChanged(QString, QString, QString)), this, SLOT(onDBusNameOwnerChanged(QString,QString,QString))); } } ServiceManager *ServiceManager::instance() { if(!instance_) { instance_ = new ServiceManager; } return instance_; } bool ServiceManager::connectToService() { if(!bioService) { bioService = new QDBusInterface(DBUS_SERVICE, DBUS_PATH, DBUS_INTERFACE, QDBusConnection::systemBus()); } return bioService->isValid(); } void ServiceManager::onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) { if(name == DBUS_SERVICE) { qDebug() << "service status changed:" << (newOwner.isEmpty() ? "inactivate" : "activate"); Q_EMIT serviceStatusChanged(!newOwner.isEmpty()); } Q_EMIT dbusNameOwnerChanged(name,oldOwner,newOwner); } /*! * \brief checkServiceExist * 检查生物识别后台服务是否已启动 */ bool ServiceManager::serviceExists() { QDBusReply reply = dbusService->call("NameHasOwner", DBUS_SERVICE); if(!reply.isValid()) { qDebug() << "check service exists error:" << reply.error(); return false; } return reply.value(); } ukui-biometric-auth/uniauth-backend/src/main.cpp0000664000175000017500000000246615167732631020673 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include "serviceinterface.h" #include "personalizeddata.h" #include #include int main(int argc, char *argv[]) { syslog(LOG_INFO, "[uniauth-backend] start begin!"); initUkuiLog4qt("ukui-biometric-uniauth"); QCoreApplication a(argc, argv); syslog(LOG_INFO, "[uniauth-backend] KYLINUSERDATAMNG initing!"); KYLINUSERDATAMNG::instance(); syslog(LOG_INFO, "[uniauth-backend] KYLINUSERDATAMNG inited!"); ServiceInterface serviveInterface; Q_UNUSED(serviveInterface); syslog(LOG_INFO, "[uniauth-backend] qcoreapplication eventloop begin!"); return a.exec(); } ukui-biometric-auth/uniauth-backend/src/CSingleton.h0000664000175000017500000000266415167732644021465 0ustar fengfeng/* * Copyright (C) 2023 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef KYSINGLETON_H #define KYSINGLETON_H template class KySingleTon { public: // 创建单例实例 template static T *instance(Args &&... args) { if (m_pSingleInstance == nullptr) { m_pSingleInstance = new T(std::forward(args)...); } return m_pSingleInstance; } // 获取单例 static T *getInstance() { return m_pSingleInstance; } // 删除单例 static void destroyInstance() { delete m_pSingleInstance; m_pSingleInstance = nullptr; } private: KySingleTon(); virtual ~KySingleTon(); private: static T *m_pSingleInstance; }; template T *KySingleTon::m_pSingleInstance = nullptr; #endif ukui-biometric-auth/uniauth-backend/src/personalizeddata.h0000664000175000017500000001074015167732644022743 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef PERSONALIZEDDATA_H #define PERSONALIZEDDATA_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ukui-log4qt.h" #include "CSingleton.h" class PersonalizedData : public QObject { Q_OBJECT public: explicit PersonalizedData(QString user); virtual ~PersonalizedData(); ////////////////////ukui-greeter-conf////////////////////////////// QString dateType(void) { return m_dateType; } void dateType(QString val) { m_dateType = val; } int fontSize(void) { return m_fontSize; } void fontSize(int val) { m_fontSize = val; } int timeType(void) { return m_timeType; } void timeType(int val) { m_timeType = val; } QString backgroundPath(void) { return m_backgroundPath; } void backgroundPath(QString val) { m_backgroundPath = val; } QString color(void) { return m_color; } void color(QString val) { m_color = val; } /////////////////////usd-ukui-settings-daemon//////////////////////////////// int cursor_size(void) { return m_cursor_size; } void cursor_size(int val) { m_cursor_size = val; } QString cursor_theme(void) { return m_cursor_theme; } void cursor_theme(QString val) { m_cursor_theme = val; } int scaling_factor(void) { return m_scaling_factor; } void scaling_factor(int val) { m_scaling_factor = val; } void getJsonData(QJsonObject &json); QString getJsonData(void); protected slots: void fileChanged(const QString &path); void directoryChanged(const QString &path); virtual void timerEvent(QTimerEvent *event); private: int __load_conf_ukuigreeterconf(void); int __load_conf_usd_conf(void); QString __copy_file(QString); protected: // ukui-greeter-conf QString m_dateType = "cn"; int m_fontSize = 5; int m_timeType = 24; QString m_backgroundPath; QString m_color; // usd-ukui-settings-daemon int m_cursor_size = 48; QString m_cursor_theme; int m_scaling_factor = 1; // 用户名 QString m_user; QFileSystemWatcher *m_file_watch = nullptr; QString m_greeter_conf_path; bool m_greeter_conf_path_changed = false; QString m_usd_conf_path; QString m_user_path; bool m_usd_conf_path_changed = false; int m_conf_TimerID = 0; }; typedef QSharedPointer KylinUserDatePtr; ///////////////////////////////////////////////// /// \brief The PersonalizedDataMng class /// class PersonalizedDataMng : public QObject { Q_OBJECT protected: explicit PersonalizedDataMng(void); virtual ~PersonalizedDataMng(); public: QString GetConfInformation(QString); void SetLoginSynInformation(QString val); signals: void conf_changed(QString jsonstr); protected Q_SLOTS: void onUserAdded(const QDBusObjectPath &path); void onUserDeleted(const QDBusObjectPath &path); protected: void __updateUsersInfo(); private: void initData(); QString getUserName(const QString &userPath); protected: QMap m_userPersonalizedData; QString m_lightdm_str; friend class KySingleTon; private: bool m_isDataInited = false; QDBusInterface *m_actService = nullptr; QMap m_mapUserPaths; }; typedef KySingleTon KYLINUSERDATAMNG; #endif // PERSONALIZEDDATA_H ukui-biometric-auth/uniauth-backend/src/servicemanager.h0000664000175000017500000000301615167732631022377 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef SERVICEMANAGER_H #define SERVICEMANAGER_H #include #include class ServiceManager : public QObject { Q_OBJECT public: static ServiceManager *instance(); bool serviceExists(); private: explicit ServiceManager(QObject *parent = nullptr); void init(); bool connectToService(); Q_SIGNALS: void serviceStatusChanged(bool activate); void dbusNameOwnerChanged(QString name,QString oldOwner,QString newOwner); public Q_SLOTS: void onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); private: static ServiceManager *instance_; QDBusInterface *dbusService; QDBusInterface *bioService; bool serviceStatus; }; #endif // SERVICEMANAGER_H ukui-biometric-auth/uniauth-backend/src/rsac.h0000664000175000017500000000275515167732631020345 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef RSAC_H #define RSAC_H #include /** * @brief The RSAC class * RSA算法相关实现,包括密钥对生成,加密与解密,签名与验签。 */ class RSAC { public: // 生成秘钥对 void generateKeyPair(const QString& priKeyFile, const QString &pubKeyFile, int bits = 1024); void generateKeyPair(QByteArray& priKey, QByteArray& pubKey, int bits = 1024); // 对数据进行加解密 bool encrypt(const QByteArray& in, QByteArray& out, const QByteArray& pubKey); bool decrypt(const QByteArray& in, QByteArray& out, const QByteArray& priKey); // 对摘要进行签名和验签 bool sign(const QByteArray& digest, QByteArray& sign, const QByteArray &priKey); bool verify(const QByteArray& digest, const QByteArray &sign, const QByteArray &pubKey); }; #endif // RSAC_H ukui-biometric-auth/uniauth-backend/src/rsac.cpp0000664000175000017500000001442115167732644020675 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "rsac.h" #include #include RSA* publicKeyToRSA(const QByteArray &pubKey) { BIO *pBio = BIO_new_mem_buf(pubKey.data(), pubKey.size()); // 创建内存 RSA* rsa = PEM_read_bio_RSA_PUBKEY(pBio, nullptr, nullptr, nullptr); BIO_free_all(pBio); // 释放内存 return rsa; } RSA* privateKeyToRSA(const QByteArray &priKey) { BIO *pBio = BIO_new_mem_buf(priKey.data(), priKey.size()); // 创建内存 RSA* rsa = PEM_read_bio_RSAPrivateKey(pBio, nullptr, nullptr, nullptr); BIO_free_all(pBio); // 释放内存 return rsa; } /** * @brief RSAC::generateKeyPair * 生成密钥对,并分别保存为文件 * @param priKeyFile 私钥文件名 * @param pubKeyFile 公钥文件名 * @param bits 秘钥长度,一般建议1024及以上 */ void RSAC::generateKeyPair(const QString &priKeyFile, const QString &pubKeyFile, int bits) { // 生成公钥 RSA* rsa = RSA_generate_key(bits, RSA_F4, nullptr, nullptr); BIO *bp = BIO_new(BIO_s_file()); BIO_write_filename(bp, (void*)pubKeyFile.toStdString().c_str()); PEM_write_bio_RSAPublicKey(bp, rsa); BIO_free_all(bp); // 生成私钥 bp = BIO_new(BIO_s_file()); BIO_write_filename(bp, (void*)priKeyFile.toStdString().c_str()); PEM_write_bio_RSAPrivateKey(bp, rsa, nullptr, nullptr, 0, nullptr, nullptr); CRYPTO_cleanup_all_ex_data(); BIO_free_all(bp); RSA_free(rsa); } /** * @brief RSAC::generateKeyPair * 生成密钥对数据 * @param privateKey 私钥数据 * @param publicKey 公钥数据 * @param bits 秘钥长度,一般建议1024及以上 */ void RSAC::generateKeyPair(QByteArray &privateKey, QByteArray &pubKey, int bits) { // 生成密钥对 RSA *keyPair = RSA_generate_key(bits, RSA_F4, nullptr, nullptr); BIO *pri = BIO_new(BIO_s_mem()); BIO *pub = BIO_new(BIO_s_mem()); PEM_write_bio_RSAPrivateKey(pri, keyPair, nullptr, nullptr, 0, nullptr, nullptr); PEM_write_bio_RSA_PUBKEY(pub, keyPair); // 获取长度 int pri_len = BIO_pending(pri); int pub_len = BIO_pending(pub); privateKey.resize(pri_len); pubKey.resize(pub_len); BIO_read(pri, privateKey.data(), pri_len); BIO_read(pub, pubKey.data(), pub_len); // 内存释放 RSA_free(keyPair); BIO_free_all(pub); BIO_free_all(pri); } /** * @brief RSAC::encrypt * RSA加密函数,使用公钥对输入数据,进行加密 * @param in 输入数据(明文) * @param out 输出数据(密文) * @param pubKey 公钥 * @return 执行结果 */ bool RSAC::encrypt(const QByteArray &in, QByteArray &out, const QByteArray& pubKey) { // 公钥数据转RSA RSA* rsa = publicKeyToRSA(pubKey); if (rsa == nullptr) { return false; } // 对任意长度数据进行加密,超长时,进行分段加密 int keySize = RSA_size(rsa); int dataLen = in.size(); const unsigned char *from = (const unsigned char *)in.data(); QByteArray to(keySize, 0); int readLen = 0; do { int select = (keySize - 11) > dataLen ? dataLen : (keySize - 11); RSA_public_encrypt(select, (from + readLen), (unsigned char *)to.data(), rsa, RSA_PKCS1_OAEP_PADDING); dataLen -= select; readLen += select; out.append(to); }while (dataLen > 0); RSA_free(rsa); return true; } /** * @brief RSAC::private_decrypt * RSA解密函数,使用私钥对输入数据,进行解密 * @param in 输入数据(密文) * @param out 输出数据(解密后的内容) * @param priKey 私钥 * @return 执行结果 */ bool RSAC::decrypt(const QByteArray &in, QByteArray &out, const QByteArray& priKey) { // 私钥数据转RSA RSA* rsa = privateKeyToRSA(priKey); if (rsa == nullptr) { return false; } // 对任意长度数据进行解密,超长时,进行分段解密 int keySize = RSA_size(rsa); int dataLen = in.size(); const unsigned char *from = (const unsigned char *)in.data(); QByteArray to(keySize, 0); int readLen = 0; do { int size = RSA_private_decrypt(keySize, (from + readLen), (unsigned char *)to.data(), rsa, RSA_PKCS1_OAEP_PADDING); dataLen -= keySize; readLen += keySize; out.append(to.data(), size); }while (dataLen > 0); RSA_free(rsa); return true; } /** * @brief RSAC::sign * 使用私钥对摘要数据进行签名 * @param digest 摘要数据 * @param sign 签名后的数据 * @param priKey 私钥 * @return 执行结果 */ bool RSAC::sign(const QByteArray &digest, QByteArray &sign, const QByteArray& priKey) { // 私钥数据转RSA RSA* rsa = privateKeyToRSA(priKey); if (rsa == nullptr) { return false; } // 对digest进行签名 unsigned int siglen = 0; QByteArray temp(RSA_size(rsa), 0); RSA_sign(NID_sha1, (const unsigned char*)digest.data(), digest.size(), (unsigned char*)temp.data(), &siglen, rsa); sign.clear(); sign.append(temp.data(), siglen); RSA_free(rsa); return true; } /** * @brief RSAC::verify * 使用公钥对摘要数据进行验签 * @param digest 摘要数据 * @param sign 签名后的数据 * @param pubKey 公钥 * @return 执行结果 */ bool RSAC::verify(const QByteArray &digest, const QByteArray &sign, const QByteArray& pubKey) { // 公钥数据转RSA RSA* rsa = publicKeyToRSA(pubKey); if (rsa == nullptr) { return false; } // 对digest、sign进行验签 int ret = RSA_verify(NID_sha1, (const unsigned char*)digest.data(), digest.size(), (const unsigned char *)sign.data(), sign.size(), rsa); RSA_free(rsa); return (ret == 1); } ukui-biometric-auth/uniauth-backend/src/biodeviceinfo.h0000664000175000017500000000347515167732631022222 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef BIODEVICEINFO_H #define BIODEVICEINFO_H #include #include #include #include struct DeviceInfo { int device_id; QString device_shortname; /* aka driverName */ QString device_fullname; int driver_enable; /* The corresponding driver is enabled/disabled */ int device_available; /* The driver is enabled and the device is connected */ int biotype; int stotype; int eigtype; int vertype; int idtype; int bustype; int dev_status; int ops_status; }; enum BioType { BIOTYPE_FINGERPRINT, BIOTYPE_FINGERVEIN, BIOTYPE_IRIS, BIOTYPE_FACE, BIOTYPE_VOICEPRINT, __MAX_NR_BIOTYPES }; #define UNIT_GENERAL_UKEY (6) #define REMOTE_QRCODE_TYPE (8) Q_DECLARE_METATYPE(DeviceInfo) Q_DECLARE_METATYPE(QList) typedef std::shared_ptr DeviceInfoPtr; typedef QList DeviceList; void registerCustomTypes(); QDBusArgument &operator<<(QDBusArgument &argument, const DeviceInfo &deviceInfo); const QDBusArgument &operator>>(const QDBusArgument &argument, DeviceInfo &deviceInfo); #endif // BIODEVICEINFO_H ukui-biometric-auth/uniauth-backend/src/greeterconfig.h0000664000175000017500000000333615167732644022240 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef GREETERCONFIG_H #define GREETERCONFIG_H #include class GreeterConfig : public QObject { Q_OBJECT public: explicit GreeterConfig(QObject *parent = nullptr); void setValue(const QString &group, const QString &key, const QVariant &value, QString strUserName = ""); QVariant getValue(const QString &group, const QString &key, QVariant varDefault, QString strUserName = ""); bool resetValue(const QString &group, const QString &key, QString strUserName = ""); QString printConfig(int nType, QString strUserName = ""); Q_SIGNALS: void changed(const QString &group, const QString &key); void changedForUser(const QString &group, const QString &key, const QString &userName); private: void initData(); void loadConfigDirectory(QString strPath); void loadConfigFromFile(QString strPath); QString getUserHomePath(const QString &strUserName); private: QSettings *m_setttingsDefault; QSettings *m_settingsCustom; QString m_strHomePath; }; #endif // LOGINCONFIG_H ukui-biometric-auth/uniauth-backend/src/biodeviceinfo.cpp0000664000175000017500000000363615167732631022554 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "biodeviceinfo.h" void registerCustomTypes() { qDBusRegisterMetaType(); qDBusRegisterMetaType >(); } QDBusArgument &operator<<(QDBusArgument &argument, const DeviceInfo &deviceInfo) { argument.beginStructure(); argument << deviceInfo.device_id << deviceInfo.device_shortname << deviceInfo.device_fullname << deviceInfo.driver_enable << deviceInfo.device_available << deviceInfo.biotype << deviceInfo.stotype << deviceInfo.eigtype << deviceInfo.vertype << deviceInfo.idtype << deviceInfo.bustype << deviceInfo.dev_status << deviceInfo.ops_status; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, DeviceInfo &deviceInfo) { argument.beginStructure(); argument >> deviceInfo.device_id >> deviceInfo.device_shortname >> deviceInfo.device_fullname >> deviceInfo.driver_enable >> deviceInfo.device_available >> deviceInfo.biotype >> deviceInfo.stotype >> deviceInfo.eigtype >> deviceInfo.vertype >> deviceInfo.idtype >> deviceInfo.bustype >> deviceInfo.dev_status >> deviceInfo.ops_status; argument.endStructure(); return argument; } ukui-biometric-auth/uniauth-backend/src/greeterconfiginterface.h0000664000175000017500000000670015167732644024117 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef GREETERCONFIGINTERFACE_H #define GREETERCONFIGINTERFACE_H #include #include #include #include "greeterconfig.h" class GreeterConfigInterface : public QObject, QDBusContext { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.UniauthBackend") public: explicit GreeterConfigInterface(QObject *parent = nullptr); public Q_SLOTS: // virutal keyboard enable void setVirtualKeyboardEnable(bool isEnable); bool getVirtualKeyboardEnable(); bool resetVirtualKeyboardEnable(); // user switch enable void setUserSwitchEnable(bool isEnable); bool getUserSwitchEnable(); bool resetUserSwitchEnable(); // network enable void setNetworkEnable(bool isEnable); bool getNetworkEnable(); bool resetNetworkEnable(); // power manager enable void setPowerManagerEnable(bool isEnable); bool getPowerManagerEnable(); bool resetPowerManagerEnable(); // lock screen datetime enable void setLockScreenDatetimeEnable(bool isEnable); bool getLockScreenDatetimeEnable(QString strUserName); bool resetLockScreenDatetimeEnable(); // screensaver datetime enable void setScreensaverDatetimeEnable(bool isEnable); bool getScreensaverDatetimeEnable(QString strUserName); bool resetScreensaverDatetimeEnable(); // login displayed user count void setLoginDisplayedUserCount(int count); int getLoginDisplayedUserCount(); bool resetLoginDisplayedUserCount(); // default select manual login bool getSelectManualLoginDefault(); /** * @brief printConfig 以json格式打印所有有效的、默认的、修改的配置项 * @param nType 1 默认配置;2 修改的配置;其他 所有有效的配置 * @return json字符串 */ QString printConfig(int nType, QString strUserName); Q_SIGNALS: void changed(const QString &group, const QString &key); void userConfigChanged(const QString &group, const QString &key, const QString &strUserName); void virtualKeyboardEnableChanged(bool isEnable); void userSwitchEnableChanged(bool isEnable); void networkEnableChanged(bool isEnable); void powerManagerEnableChanged(bool isEnable); void lockScreenDatetimeEnableChanged(bool isEnable, QString strUserName); void screensaverDatetimeChanged(bool isEnable, QString strUserName); void loginDisplayedUserCountChanged(int count); private Q_SLOTS: void onChanged(const QString &group, const QString &key); void onChangedForUser(const QString &group, const QString &key, const QString &strUserName); private: bool checkEnviron(int pid); bool isAllowedCaller(); QString getUserNameFromCaller(); private: GreeterConfig *m_config = nullptr; }; #endif // GREETERCONFIGINTERFACE_H ukui-biometric-auth/uniauth-backend/src/personalizeddata.cpp0000664000175000017500000003040215167732644023273 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "personalizeddata.h" #include #include #include #include #include #include #include #include #include #include #include #include #define LIGHTDMDATA_ROOT_PATH "/var/lib/lightdm-data/" #define ACT_DBUS_SERVICE "org.freedesktop.Accounts" #define ACT_DBUS_PATH "/org/freedesktop/Accounts" #define ACT_DBUS_INTERFACE "org.freedesktop.Accounts" #define ACT_USER_INTERFACE "org.freedesktop.Accounts.User" #define DBUS_PROP_INTERFACE "org.freedesktop.DBus.Properties" enum enum_operation { enum_operation_update = 0, enum_operation_add, enum_operation_del, }; PersonalizedData::PersonalizedData(QString user) { KyInfo() << user; m_user = user; m_usd_conf_path = QString("/var/lib/lightdm-data/%1/usd/config/ukui-settings-daemon.settings").arg(m_user); m_greeter_conf_path = QString("/var/lib/lightdm-data/%1/ukui-greeter.conf").arg(m_user); m_user_path = QString("/var/lib/lightdm-data/%1/").arg(m_user); m_file_watch = new QFileSystemWatcher(); connect(m_file_watch, &QFileSystemWatcher::fileChanged, this, &PersonalizedData::fileChanged); connect(m_file_watch, &QFileSystemWatcher::directoryChanged, this, &PersonalizedData::directoryChanged); if (this->__load_conf_ukuigreeterconf() != 0) { if (QFileInfo(m_user_path).exists()) { if (!m_file_watch->directories().contains(m_user_path)) { m_file_watch->addPath(m_user_path); } } else if (QFileInfo(LIGHTDMDATA_ROOT_PATH).exists()) { if (!m_file_watch->directories().contains(LIGHTDMDATA_ROOT_PATH)) { m_file_watch->addPath(LIGHTDMDATA_ROOT_PATH); } } qDebug() << "init ukuigreeter conf failed:" << m_user << ",monitor:" << m_file_watch->directories(); } // 无需读取usd配置 // this->__load_conf_usd_conf(); } PersonalizedData::~PersonalizedData() { KyInfo() << m_user; if (0 != m_conf_TimerID) { this->killTimer(m_conf_TimerID); m_conf_TimerID = 0; } if (nullptr != m_file_watch) { delete m_file_watch; m_file_watch = nullptr; } } void PersonalizedData::getJsonData(QJsonObject &json) { json["user"] = m_user; { QJsonObject json_1; json_1["dateType"] = m_dateType; json_1["fontSize"] = m_fontSize; json_1["timeType"] = m_timeType; json_1["backgroundPath"] = m_backgroundPath; json_1["color"] = m_color; json["greeter"] = json_1; } } QString PersonalizedData::getJsonData() { QJsonObject json; this->getJsonData(json); json["operation"] = enum_operation_update; QJsonDocument document; document.setObject(json); return document.toJson(QJsonDocument::Compact); } void PersonalizedData::fileChanged(const QString &path) { KyInfo() << path; if (m_greeter_conf_path == path) { m_greeter_conf_path_changed = true; } if (m_usd_conf_path == path) { m_usd_conf_path_changed = true; } if (0 != m_conf_TimerID) { this->killTimer(m_conf_TimerID); m_conf_TimerID = 0; } m_conf_TimerID = this->startTimer(100); } void PersonalizedData::directoryChanged(const QString &path) { qDebug() << "Dirctory Changed:" << path; if (LIGHTDMDATA_ROOT_PATH == path) { if (QFileInfo(m_user_path).exists()) { if (!m_file_watch->directories().contains(m_user_path)) { m_file_watch->addPath(m_user_path); } } else { QTimer::singleShot(100, this, [=]() { if (QFileInfo(m_user_path).exists()) { if (!m_file_watch->directories().contains(m_user_path)) { m_file_watch->addPath(m_user_path); } } }); } } else if (m_user_path == path) { if (QFileInfo(m_greeter_conf_path).exists()) { fileChanged(m_greeter_conf_path); } else { QTimer::singleShot(100, this, [=]() { if (QFileInfo(m_greeter_conf_path).exists()) { fileChanged(m_greeter_conf_path); } }); } } } void PersonalizedData::timerEvent(QTimerEvent *event) { KyInfo() << m_file_watch->files(); if (event->timerId() == m_conf_TimerID) { this->killTimer(m_conf_TimerID); m_conf_TimerID = 0; if (m_greeter_conf_path_changed) { m_greeter_conf_path_changed = false; this->__load_conf_ukuigreeterconf(); } if (m_usd_conf_path_changed) { m_usd_conf_path_changed = false; this->__load_conf_usd_conf(); } emit KYLINUSERDATAMNG::getInstance()->conf_changed(this->getJsonData()); } } int PersonalizedData::__load_conf_ukuigreeterconf() { if (!QFileInfo(m_greeter_conf_path).exists()) { KyWarning() << "config file not exist:" << m_greeter_conf_path; return -1; } QSettings conf(m_greeter_conf_path, QSettings::IniFormat); if (QSettings::NoError != conf.status()) { KyWarning() << m_greeter_conf_path << conf.status(); return -1; } if (conf.childGroups().contains("Greeter")) { conf.beginGroup("Greeter"); if (conf.contains("dateType")) m_dateType = conf.value("dateType", m_dateType).toString(); if (conf.contains("fontSize")) m_fontSize = conf.value("fontSize", m_fontSize).toInt(); if (conf.contains("timeType")) m_timeType = conf.value("timeType", m_timeType).toInt(); conf.endGroup(); } if (conf.childGroups().contains("greeter")) { conf.beginGroup("greeter"); if (conf.contains("backgroundPath")) { m_backgroundPath = conf.value("backgroundPath", m_backgroundPath).toString(); if (!m_backgroundPath.isEmpty()) { m_backgroundPath = this->__copy_file(m_backgroundPath); } } if (conf.contains("color")) m_color = conf.value("color", m_color).toString(); conf.endGroup(); } if (nullptr != m_file_watch && !m_file_watch->files().contains(m_greeter_conf_path)) { m_file_watch->addPath(m_greeter_conf_path); } return 0; } int PersonalizedData::__load_conf_usd_conf() { KyInfo(); QSettings conf(m_usd_conf_path, QSettings::IniFormat); if (QSettings::NoError != conf.status()) { KyWarning() << m_usd_conf_path << conf.status(); return -1; } if (conf.childGroups().contains("xsettings")) { conf.beginGroup("xsettings"); if (conf.contains("cursor-size")) m_cursor_size = conf.value("cursor-size", m_cursor_size).toInt(); if (conf.contains("cursor-theme")) m_cursor_theme = conf.value("cursor-theme", m_cursor_theme).toString(); if (conf.contains("scaling-factor")) m_scaling_factor = conf.value("scaling-factor", m_scaling_factor).toInt(); conf.endGroup(); } if (nullptr != m_file_watch && !m_file_watch->files().contains(m_usd_conf_path)) { m_file_watch->addPath(m_usd_conf_path); } return 0; } QString PersonalizedData::__copy_file(QString oldfile) { if (QFile::exists(oldfile)) { QString tempPath = QStandardPaths::writableLocation(QStandardPaths::TempLocation); QString newfile = QString("%1/loginBackground-%2-%3-XXXXXX") .arg(tempPath) .arg(m_user) .arg(QDate::currentDate().toString("yyyy-MM-dd")); if (QFile::exists(newfile)) { QFile::remove(newfile); } if (QFile::copy(oldfile, newfile)) { return newfile; } } return ""; } /////////////////////////PersonalizedDataMng////////////////////////////////////// PersonalizedDataMng::PersonalizedDataMng() { initData(); } void PersonalizedDataMng::initData() { if (m_isDataInited) { return; } if (!m_actService) { m_actService = new QDBusInterface(ACT_DBUS_SERVICE, ACT_DBUS_PATH, ACT_DBUS_INTERFACE, QDBusConnection::systemBus()); connect( m_actService, SIGNAL(UserAdded(const QDBusObjectPath &)), this, SLOT(onUserAdded(const QDBusObjectPath &))); connect( m_actService, SIGNAL(UserDeleted(const QDBusObjectPath &)), this, SLOT(onUserDeleted(const QDBusObjectPath &))); } this->__updateUsersInfo(); m_isDataInited = true; } QString PersonalizedDataMng::getUserName(const QString &userPath) { QDBusInterface iface(ACT_DBUS_SERVICE, userPath, DBUS_PROP_INTERFACE, QDBusConnection::systemBus()); QDBusReply reply = iface.call("Get", ACT_USER_INTERFACE, "UserName"); QString strUserName = ""; if (reply.isValid()) { strUserName = reply.value().variant().toString(); } return strUserName; } PersonalizedDataMng::~PersonalizedDataMng() {} QString PersonalizedDataMng::GetConfInformation(QString name) { QJsonObject json; if (m_userPersonalizedData.contains(name)) { QJsonObject json1; m_userPersonalizedData[name]->getJsonData(json1); json[name] = json1; } else if (name.isEmpty()) { for (auto &it : m_userPersonalizedData.toStdMap()) { QJsonObject json1; it.second->getJsonData(json1); json[it.first] = json1; } } else if ("lightdm" == name) { QString tmp(m_lightdm_str); m_lightdm_str = ""; return tmp; } QJsonDocument document; document.setObject(json); QString strJson(document.toJson(QJsonDocument::Compact)); KyDebug() << strJson; return strJson; } void PersonalizedDataMng::SetLoginSynInformation(QString val) { m_lightdm_str = val; } void PersonalizedDataMng::onUserAdded(const QDBusObjectPath &path) { QString strUserName = getUserName(path.path()); if (!strUserName.isEmpty()) { m_userPersonalizedData[strUserName] = KylinUserDatePtr(new PersonalizedData(strUserName)); m_mapUserPaths[path.path()] = strUserName; QJsonObject json; m_userPersonalizedData[strUserName]->getJsonData(json); json["operation"] = enum_operation_add; QJsonDocument document; document.setObject(json); emit conf_changed(document.toJson()); } } void PersonalizedDataMng::onUserDeleted(const QDBusObjectPath &path) { QString strUserName = m_mapUserPaths[path.path()]; if (!strUserName.isEmpty()) { m_userPersonalizedData.remove(strUserName); m_mapUserPaths.remove(path.path()); QJsonObject json; json["operation"] = enum_operation_del; json["user"] = strUserName; QJsonDocument document; document.setObject(json); emit conf_changed(document.toJson()); } } void PersonalizedDataMng::__updateUsersInfo() { if (m_actService) { QDBusMessage ret = m_actService->call("ListCachedUsers"); QList outArgs = ret.arguments(); QVariant first = outArgs.at(0); const QDBusArgument &dbusArgs = first.value(); QDBusObjectPath path; dbusArgs.beginArray(); while (!dbusArgs.atEnd()) { dbusArgs >> path; QString strUserName = getUserName(path.path()); if (!strUserName.isEmpty()) { m_userPersonalizedData[strUserName] = KylinUserDatePtr(new PersonalizedData(strUserName)); m_mapUserPaths[path.path()] = strUserName; } } dbusArgs.endArray(); } } ukui-biometric-auth/uniauth-backend/src/greeterconfiginterface.cpp0000664000175000017500000002447615167732644024464 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "greeterconfiginterface.h" #include #include #include #include #include #define GROUP_FUNCTIONS "Functions" #define KEY_USER_SWITCH_ENABLE "UserSwitchEnable" #define KEY_VIRTUAL_KEYBOARD_ENABLE "VirtualKeyBoardEnable" #define KEY_NETWORK_ENABLE "NetworkEnable" #define KEY_POWERMANAGER_ENABLE "PowerManagerEnable" #define KEY_LOCKSCREEN_SHOWDATETIME_ENABLE "LockScreenShowDatetimeEnable" #define KEY_SCREENSAVER_SHOWDATETIME_ENABLE "ScreensaverShowDatetimeEnable" #define KEY_LOGIN_DISPLAYED_USER_COUNT "LoginDisplayedUserCount" #define KEY_SELECT_MANUAL_LOGIN_DEFAULT "SelectManualLoginDefault" #define GROUP_GREETER "Greeter" GreeterConfigInterface::GreeterConfigInterface(QObject *parent) : QObject(parent) { m_config = new GreeterConfig(this); connect(m_config, &GreeterConfig::changed, this, &GreeterConfigInterface::changed); connect(m_config, &GreeterConfig::changedForUser, this, &GreeterConfigInterface::userConfigChanged); connect(m_config, &GreeterConfig::changed, this, &GreeterConfigInterface::onChanged); connect(m_config, &GreeterConfig::changedForUser, this, &GreeterConfigInterface::onChangedForUser); } void GreeterConfigInterface::onChanged(const QString &group, const QString &key) { if (group == GROUP_FUNCTIONS) { if (key == KEY_VIRTUAL_KEYBOARD_ENABLE) { Q_EMIT virtualKeyboardEnableChanged(getVirtualKeyboardEnable()); } else if (key == KEY_NETWORK_ENABLE) { Q_EMIT networkEnableChanged(getNetworkEnable()); } else if (key == KEY_USER_SWITCH_ENABLE) { Q_EMIT userSwitchEnableChanged(getUserSwitchEnable()); } else if (key == KEY_POWERMANAGER_ENABLE) { Q_EMIT powerManagerEnableChanged(getPowerManagerEnable()); } else if (key == KEY_LOGIN_DISPLAYED_USER_COUNT) { Q_EMIT loginDisplayedUserCountChanged(getLoginDisplayedUserCount()); } } } void GreeterConfigInterface::onChangedForUser(const QString &group, const QString &key, const QString &strUserName) { if (group == GROUP_FUNCTIONS) { if (key == KEY_LOCKSCREEN_SHOWDATETIME_ENABLE) { Q_EMIT lockScreenDatetimeEnableChanged(getLockScreenDatetimeEnable(strUserName), strUserName); } else if (key == KEY_SCREENSAVER_SHOWDATETIME_ENABLE) { Q_EMIT screensaverDatetimeChanged(getScreensaverDatetimeEnable(strUserName), strUserName); } } } void GreeterConfigInterface::setLoginDisplayedUserCount(int count) { if (!isAllowedCaller()) { return; } qDebug() << "setLoginDisplayedUserCount:" << count; m_config->setValue(GROUP_FUNCTIONS, KEY_LOGIN_DISPLAYED_USER_COUNT, count); } int GreeterConfigInterface::getLoginDisplayedUserCount() { return m_config->getValue(GROUP_FUNCTIONS, KEY_LOGIN_DISPLAYED_USER_COUNT, -1).toInt(); } bool GreeterConfigInterface::resetLoginDisplayedUserCount() { if (!isAllowedCaller()) { return false; } qDebug() << "resetLoginDisplayedUserCount!"; return m_config->resetValue(GROUP_FUNCTIONS, KEY_LOGIN_DISPLAYED_USER_COUNT); } void GreeterConfigInterface::setVirtualKeyboardEnable(bool isEnable) { if (!isAllowedCaller()) { return; } qDebug() << "setVirtualKeyboardEnable:" << isEnable; m_config->setValue(GROUP_FUNCTIONS, KEY_VIRTUAL_KEYBOARD_ENABLE, isEnable); } bool GreeterConfigInterface::getVirtualKeyboardEnable() { return m_config->getValue(GROUP_FUNCTIONS, KEY_VIRTUAL_KEYBOARD_ENABLE, true).toBool(); } bool GreeterConfigInterface::resetVirtualKeyboardEnable() { if (!isAllowedCaller()) { return false; } qDebug() << "resetVirtualKeyboardEnable!"; return m_config->resetValue(GROUP_FUNCTIONS, KEY_VIRTUAL_KEYBOARD_ENABLE); } void GreeterConfigInterface::setUserSwitchEnable(bool isEnable) { if (!isAllowedCaller()) { return; } qDebug() << "setUserSwitchEnable:" << isEnable; m_config->setValue(GROUP_FUNCTIONS, KEY_USER_SWITCH_ENABLE, isEnable); } bool GreeterConfigInterface::getUserSwitchEnable() { return m_config->getValue(GROUP_FUNCTIONS, KEY_USER_SWITCH_ENABLE, true).toBool(); } bool GreeterConfigInterface::resetUserSwitchEnable() { if (!isAllowedCaller()) { return false; } qDebug() << "resetUserSwitchEnable!"; return m_config->resetValue(GROUP_FUNCTIONS, KEY_USER_SWITCH_ENABLE); } void GreeterConfigInterface::setNetworkEnable(bool isEnable) { if (!isAllowedCaller()) { return; } qDebug() << "setNetworkEnable:" << isEnable; m_config->setValue(GROUP_FUNCTIONS, KEY_NETWORK_ENABLE, isEnable); } bool GreeterConfigInterface::getNetworkEnable() { return m_config->getValue(GROUP_FUNCTIONS, KEY_NETWORK_ENABLE, true).toBool(); } bool GreeterConfigInterface::resetNetworkEnable() { if (!isAllowedCaller()) { return false; } qDebug() << "resetNetworkEnable!"; return m_config->resetValue(GROUP_FUNCTIONS, KEY_NETWORK_ENABLE); } void GreeterConfigInterface::setPowerManagerEnable(bool isEnable) { if (!isAllowedCaller()) { return; } qDebug() << "setPowerManagerEnable:" << isEnable; m_config->setValue(GROUP_FUNCTIONS, KEY_POWERMANAGER_ENABLE, isEnable); } bool GreeterConfigInterface::getPowerManagerEnable() { return m_config->getValue(GROUP_FUNCTIONS, KEY_POWERMANAGER_ENABLE, true).toBool(); } bool GreeterConfigInterface::resetPowerManagerEnable() { if (!isAllowedCaller()) { return false; } qDebug() << "resetPowerManagerEnable!"; return m_config->resetValue(GROUP_FUNCTIONS, KEY_POWERMANAGER_ENABLE); } // lock screen datetime enable void GreeterConfigInterface::setLockScreenDatetimeEnable(bool isEnable) { if (!isAllowedCaller()) { return; } QString userName = getUserNameFromCaller(); qDebug() << "setLockScreenDatetimeEnable:" << isEnable << "," << userName; m_config->setValue(GROUP_FUNCTIONS, KEY_LOCKSCREEN_SHOWDATETIME_ENABLE, isEnable, userName); } bool GreeterConfigInterface::getLockScreenDatetimeEnable(QString strUserName) { return m_config->getValue(GROUP_FUNCTIONS, KEY_LOCKSCREEN_SHOWDATETIME_ENABLE, true, strUserName).toBool(); } bool GreeterConfigInterface::resetLockScreenDatetimeEnable() { if (!isAllowedCaller()) { return false; } QString userName = getUserNameFromCaller(); qDebug() << "resetLockScreenDatetimeEnable:" << userName; return m_config->resetValue(GROUP_FUNCTIONS, KEY_LOCKSCREEN_SHOWDATETIME_ENABLE, userName); } // screensaver datetime enable void GreeterConfigInterface::setScreensaverDatetimeEnable(bool isEnable) { if (!isAllowedCaller()) { return; } QString userName = getUserNameFromCaller(); qDebug() << "setScreensaverDatetimeEnable:" << isEnable << "," << userName; m_config->setValue(GROUP_FUNCTIONS, KEY_SCREENSAVER_SHOWDATETIME_ENABLE, isEnable, userName); } bool GreeterConfigInterface::getScreensaverDatetimeEnable(QString strUserName) { return m_config->getValue(GROUP_FUNCTIONS, KEY_SCREENSAVER_SHOWDATETIME_ENABLE, true, strUserName).toBool(); } bool GreeterConfigInterface::resetScreensaverDatetimeEnable() { if (!isAllowedCaller()) { return false; } QString userName = getUserNameFromCaller(); qDebug() << "resetScreensaverDatetimeEnable:" << userName; return m_config->resetValue(GROUP_FUNCTIONS, KEY_SCREENSAVER_SHOWDATETIME_ENABLE, userName); } bool GreeterConfigInterface::getSelectManualLoginDefault() { return m_config->getValue(GROUP_GREETER, KEY_SELECT_MANUAL_LOGIN_DEFAULT, false).toBool(); } QString GreeterConfigInterface::printConfig(int nType, QString strUserName) { return m_config->printConfig(nType, strUserName); } bool GreeterConfigInterface::checkEnviron(int pid) { QString filePath = QString("/proc/%1/environ").arg(pid); QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "file.open failed" << filePath; return false; } QTextStream in(&file); QString data = in.readAll(); file.close(); data.replace('\0', '\n'); QStringList environVars = data.split('\n'); for (const QString &var : environVars) { if (!var.isEmpty()) { int pos = var.indexOf('='); if (pos != -1) { QString key = var.left(pos); if (key == "LD_PRELOAD" || key == "LD_LIBRARY_PATH" || key == "LD_AUDIT") { return false; } } } } return true; } bool GreeterConfigInterface::isAllowedCaller() { // QString clientService = message().service(); // QDBusConnectionInterface *intf = connection().interface(); // unsigned int pid = intf->servicePid(clientService).value(); // /*check caller environ*/ // if (!checkEnviron(pid)) { // sendErrorReply(QDBusError::ErrorType::Failed, QString("[%2] dbus method control,env // forbidden").arg((pid))); return false; // } // /*check caller info*/ // QFileInfo file(QString("/proc/%1/exe").arg(pid)); // QString execPath = ""; // if (file.exists()) { // execPath = file.canonicalFilePath(); // } // qDebug() << "Caller info(uid,pid,ppath):" << intf->serviceUid(clientService).value() << pid << execPath; return true; } QString GreeterConfigInterface::getUserNameFromCaller() { QString clientService = message().service(); QDBusConnectionInterface *intf = connection().interface(); int uid = intf->serviceUid(clientService).value(); struct passwd *pwinfo = getpwuid(uid); if (pwinfo && pwinfo->pw_name) { return QString(pwinfo->pw_name); } else { return QString(""); } } ukui-biometric-auth/uniauth-backend/src/serviceinterface.h0000664000175000017500000001673515167732644022745 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef SERVICEINTERFACE_H #define SERVICEINTERFACE_H #include "biodeviceinfo.h" #include #include #include #include #include #include #include "rsac.h" #include "greeterconfiginterface.h" #define DBUS_SERVICE "org.ukui.Biometric" #define DBUS_PATH "/org/ukui/Biometric" #define DBUS_INTERFACE "org.ukui.Biometric" enum authEnableType { ENABLETYPE_BIO, // 全局总使能 ENABLETYPE_SAVER, // 锁屏 ENABLETYPE_GREETER, // 登录 ENABLETYPE_POLKIT, // 授权 ENABLETYPE_SU, // 暂保留 ENABLETYPE_SUDO, // 暂保留 ENABLETYPE_LOGIN, // 暂保留 }; /** * @brief 用户信息 */ struct WillLoginUserInfo { QString strUserName = ""; bool isOneKeyLogin = false; }; QDBusArgument &operator<<(QDBusArgument &arg, const WillLoginUserInfo &willLoginUserInfo); const QDBusArgument &operator>>(const QDBusArgument &arg, WillLoginUserInfo &willLoginUserInfo); QDebug operator<<(QDebug stream, const WillLoginUserInfo &willLoginUserInfo); Q_DECLARE_METATYPE(WillLoginUserInfo) class ServiceInterface : public QObject, protected QDBusContext { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.ukui.UniauthBackend") public: ServiceInterface(); public slots: // 设置默认设备 void setDefaultDevice(int bioDevType, QString deviceName); // 获取默认设备 QString getDefaultDevice(QString userName, int bioDevType); // 获取所有默认设备 QStringList getAllDefaultDevice(QString userName); // 生物特征开关接口 bool getBioAuthStatus(QString userName, int bioAuthType); void setBioAuthStatus(int bioAuthType, bool status); // 获取最大失败次数 int getMaxFailedTimes(); // 获取人脸识别超时停用次数 int getFTimeoutTimes(); // 设置人脸识别超时停用次数 void setFTimeoutTimes(int times); // 获取是否使能微信扫码登录 bool getQRCodeEnable(); // 获取是否双认证 bool getDoubleAuth(); // 获取用户绑定 bool getUserBind(); // 获取是否在控制面板显示 bool getIsShownInControlCenter(); // 获取是否使用第一个设备 bool getUseFirstDevice(); // 获取是否隐藏切换按钮 bool getHiddenSwitchButton(); // 记录当前正在进行生物认证的设备 void recordAuthDrive(QString appName, int drvid, bool insert); // 获取当前正在进行生物认证的应用 QStringList getAllAuthApp(); // 获取当前应用在认证的驱动 int getAppAuthDrive(QString appName); // 获取用户配置 QString GetUserInformation(QString username); // 同步登录界面配置 void SetLoginSynInformation(QString val); // 获取公钥 QString getPublicEncrypt(); // 发送用户名和密码 bool sendPassword(QString username, QByteArray password); // 前端注册到后端接口 bool registerLoginApp(); // 发送认证结果 bool sendSignalLoginFinished(QString username, bool res); /** * @brief 一键切换并登录用户 * * @param strUserName 用户名 * @return int 0 成功,否则失败 */ int SwitchToUser(QString strUserName); /** * @brief 切换到登录用户 * * @param strUserName 用户名 * @return int 0 成功,否则失败 */ int SwitchToGreeterUser(QString strUserName); /** * @brief 获取将要登录的用户名 * * @return WillLoginUserInfo 用户信息 */ WillLoginUserInfo getWillSwitchUser(); /** * @brief SaveLastLoginUser 记录上一次登录成功的用户 * @param strUserName 用户名 * @return 0 成功,其他失败 */ int SaveLastLoginUser(QString strUserName); /** * @brief GetLastLoginUser 获取上一次登录的用户 * @return 用户名 */ QString GetLastLoginUser(); /** * @brief SaveQuickLoginUser 保存下次快速登录的用户 * @param strUserName 用户名 * @return 0 成功,其他失败 */ int SaveQuickLoginUser(QString strUserName); /** * @brief GetQuickLoginUser 获取快速登录的用户名 * @return 用户名 */ QString GetQuickLoginUser(); private slots: void onUSBDeviceHotPlug(int drvid, int action, int deviceNum); void onBiometricDbusChanged(bool bActive); void onDbusNameOwnerChanged(QString name, QString oldOwner, QString newOwner); signals: // 默认设备改变 void defaultDeviceChanged(QString userName, int bioDevType, QString deviceName); // 开关状态改变 void bioAuthStatusChanged(QString userName, int type, bool status); // 用户配置改变 void updateUserInformation(QString jsonstring); // 单点登录完成信号 void onSignalLoginFinished(QString username, bool res); // 登录服务以启动信号 void onLoginServicdRegisted(); /** * @brief 将要登录的用户名改变 * * @param willLoginUser 新用户信息(需对空用户名异常处理) */ void userChanged(WillLoginUserInfo willLoginUser); private: // 设置默认设备 void setDefaultDevice(QString userName, int bioDevType, QString deviceName); // 设置通用默认设备 void setCommDefaultDevice(int bioDevType, QString deviceName); // 获取通用默认设备 QString getCommDefaultDevice(int bioDevType); // 获取旧版app使能值 int getOldAppStatus(); // 初始化数据 void initData(); // 更新通用默认设备 void updateCommDefaultDevice(int nDriId); // 等待生物识别服务 void waitBiometricServiceStatus(); // 判断系统是否为990 void checkIs990(); // 获取系统是否为990 bool getIs990(); // 根据pid获取进程名称 QString getProcessNameFromPid(int pid); // 根据uid获取用户名 QString getUserNameFromUid(int uid); // 获取登录锁屏界面的公钥 QString getLoginPubKey(QString service, QString path, QString interface); // 发送密码到登录锁屏界面 bool sendLoginPassword(QString service, QString path, QString interface, QString username, QByteArray array); // 处理首次登录逻辑 bool handleFirstSingleLogn(QString username, QByteArray decryptText); private: QDBusInterface *m_serviceInterface = nullptr; DeviceList m_listDeviceInfos; int deviceCount = 0; bool is990 = false; bool m_isDataInited = false; QMap m_AuthingDriveList; QMap loginAppList; RSAC rsac; QByteArray priKey, pubKey; bool isFirstLogin = true; bool hasSaveLogin = false; QString savedUsername; QByteArray savedPassword; GreeterConfigInterface *m_greeterConfigInterface = nullptr; WillLoginUserInfo m_willLoginUser; /** 将登录的用户信息 */ }; #endif // SERVICEINTERFACE_H ukui-biometric-auth/uniauth-backend/src/serviceinterface.cpp0000664000175000017500000012716515167732644023300 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "serviceinterface.h" #include #include #include #if QT_VERSION_MAJOR == 6 #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "servicemanager.h" #include "personalizeddata.h" #include #include #include #include #define UKUI_GREETER "/usr/sbin/ukui-greeter" #define UKUI_SCREENSAVER "/usr/bin/ukui-screensaver-backend" #define GREETER_DBUS_PATH "/" #define GREETER_DBUS_INTERFACE "org.ukui.greeter" #define SCREENSAVER_DBUS_PATH "/" #define SCREENSAVER_DBUS_INTERFACE "org.ukui.screensaver" #define COMM_CONFIG_PATH "/etc/biometric-auth/ukui-biometric.conf" #define USER_CONFIG_PATH "/home/%1/.biometric_auth/ukui_biometric.conf" #define OLD_990_USER_CONFIG_PATH "/home/%1/.biometric-auth/ukui-biometric.conf" #define PROC_CPUINFO "/proc/cpuinfo" #define LAST_LOGIN_INFO_PATH "/var/lib/lightdm/.cache/ukui-greeter.conf" /* For the type WillLoginUserInfo */ QDBusArgument &operator<<(QDBusArgument &argument, const WillLoginUserInfo &willLoginUserInfo) { argument.beginStructure(); argument << willLoginUserInfo.strUserName << willLoginUserInfo.isOneKeyLogin; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, WillLoginUserInfo &willLoginUserInfo) { argument.beginStructure(); argument >> willLoginUserInfo.strUserName >> willLoginUserInfo.isOneKeyLogin; argument.endStructure(); return argument; } QDebug operator<<(QDebug stream, const WillLoginUserInfo &willLoginUserInfo) { stream << "WillLogUser [" << willLoginUserInfo.strUserName << willLoginUserInfo.isOneKeyLogin << "]"; return stream; } ServiceInterface::ServiceInterface() { syslog(LOG_INFO, "[uniauth-backend] ServiceInterface init begin"); bool res = QDBusConnection::systemBus().registerService("org.ukui.UniauthBackend"); if (!res) { qInfo() << "registerService org.ukui.UniauthBackend failed!!"; exit(0); } res = QDBusConnection::systemBus().registerObject( "/org/ukui/UniauthBackend", "org.ukui.UniauthBackend", this, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals); if (!res) { qInfo() << "registerObject /org/ukui/UniauthBackend failed!!"; exit(0); } m_greeterConfigInterface = new GreeterConfigInterface(this); res = QDBusConnection::systemBus().registerObject( "/org/ukui/GreeterConfig", "org.ukui.UniauthBackend", m_greeterConfigInterface, QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllSignals); if (!res) { qInfo() << "registerObject /org/ukui/GreeterConfig failed!!"; } registerCustomTypes(); qRegisterMetaType("WillLoginUserInfo"); qDBusRegisterMetaType(); checkIs990(); m_serviceInterface = new QDBusInterface(DBUS_SERVICE, DBUS_PATH, DBUS_INTERFACE, QDBusConnection::systemBus(), this); m_serviceInterface->setTimeout(2147483647); connect(m_serviceInterface, SIGNAL(USBDeviceHotPlug(int, int, int)), this, SLOT(onUSBDeviceHotPlug(int, int, int))); ServiceManager *sm = ServiceManager::instance(); connect(sm, &ServiceManager::serviceStatusChanged, this, &ServiceInterface::onBiometricDbusChanged); connect( KYLINUSERDATAMNG::getInstance(), &PersonalizedDataMng::conf_changed, this, &ServiceInterface::updateUserInformation); syslog(LOG_INFO, "[uniauth-backend] ServiceInterface init end"); } void ServiceInterface::setDefaultDevice(QString userName, int bioDevType, QString deviceName) { QString configPath = QString(USER_CONFIG_PATH).arg(userName); qDebug() << configPath << bioDevType; QSettings settings(configPath, QSettings::IniFormat); switch (bioDevType) { case BIOTYPE_FACE: settings.setValue("FC_DefaultDevice", deviceName); break; case BIOTYPE_FINGERPRINT: settings.setValue("FP_DefaultDevice", deviceName); break; case BIOTYPE_FINGERVEIN: settings.setValue("FV_DefaultDevice", deviceName); break; case BIOTYPE_IRIS: settings.setValue("IR_DefaultDevice", deviceName); break; case BIOTYPE_VOICEPRINT: settings.setValue("VP_DefaultDevice", deviceName); break; case UNIT_GENERAL_UKEY: settings.setValue("GU_DefaultDevice", deviceName); break; case REMOTE_QRCODE_TYPE: settings.setValue("WC_DefaultDevice", deviceName); break; default: break; } settings.sync(); qDebug() << "setDefaultDevice:" << userName << "," << bioDevType << "," << deviceName; emit defaultDeviceChanged(userName, bioDevType, deviceName); } void ServiceInterface::setDefaultDevice(int bioDevType, QString deviceName) { QDBusConnection conn = connection(); QDBusMessage msg = message(); int uid = conn.interface()->serviceUid(msg.service()).value(); struct passwd *pwinfo = getpwuid(uid); if (pwinfo && pwinfo->pw_name) { setDefaultDevice(pwinfo->pw_name, bioDevType, deviceName); } else { qInfo() << "GetPWInfo failed!!"; } } QString ServiceInterface::getDefaultDevice(QString userName, int bioDevType) { initData(); QString defaultDevice = ""; QString configPath = QString(USER_CONFIG_PATH).arg(userName); QSettings settings(configPath, QSettings::IniFormat); // 获取用户旧的默认设备 if (settings.contains("DefaultDevice")) { QString strOldDefDev = settings.value("DefaultDevice").toString(); if (!strOldDefDev.isEmpty()) { for (auto devInfo : m_listDeviceInfos) { if (devInfo && devInfo->device_shortname == strOldDefDev) { QString strBioDefType = ""; switch (devInfo->biotype) { case BIOTYPE_FINGERPRINT: strBioDefType = "FP_DefaultDevice"; break; case BIOTYPE_FINGERVEIN: strBioDefType = "FV_DefaultDevice"; break; case BIOTYPE_IRIS: strBioDefType = "IR_DefaultDevice"; break; case BIOTYPE_FACE: strBioDefType = "FC_DefaultDevice"; break; case BIOTYPE_VOICEPRINT: strBioDefType = "VP_DefaultDevice"; break; case UNIT_GENERAL_UKEY: strBioDefType = "GU_DefaultDevice"; break; case REMOTE_QRCODE_TYPE: strBioDefType = "WC_DefaultDevice"; break; default: break; } if (!strBioDefType.isEmpty() && !settings.contains(strBioDefType)) { settings.setValue(strBioDefType, strOldDefDev); settings.setValue("DefaultDevice", ""); settings.sync(); } if (bioDevType == devInfo->biotype) { return strOldDefDev; } break; } } } } switch (bioDevType) { case BIOTYPE_FACE: defaultDevice = settings.value("FC_DefaultDevice").toString(); break; case BIOTYPE_FINGERPRINT: defaultDevice = settings.value("FP_DefaultDevice").toString(); break; case BIOTYPE_FINGERVEIN: defaultDevice = settings.value("FV_DefaultDevice").toString(); break; case BIOTYPE_IRIS: defaultDevice = settings.value("IR_DefaultDevice").toString(); break; case BIOTYPE_VOICEPRINT: defaultDevice = settings.value("VP_DefaultDevice").toString(); break; case UNIT_GENERAL_UKEY: defaultDevice = settings.value("GU_DefaultDevice").toString(); break; case REMOTE_QRCODE_TYPE: defaultDevice = settings.value("WC_DefaultDevice").toString(); break; default: defaultDevice = settings.value("DefaultDevice").toString(); break; } if (defaultDevice.isEmpty()) { QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat); switch (bioDevType) { case BIOTYPE_FACE: defaultDevice = settings2.value("FC_DefaultDevice").toString(); break; case BIOTYPE_FINGERPRINT: defaultDevice = settings2.value("FP_DefaultDevice").toString(); break; case BIOTYPE_FINGERVEIN: defaultDevice = settings2.value("FV_DefaultDevice").toString(); break; case BIOTYPE_IRIS: defaultDevice = settings2.value("IR_DefaultDevice").toString(); break; case BIOTYPE_VOICEPRINT: defaultDevice = settings2.value("VP_DefaultDevice").toString(); break; case UNIT_GENERAL_UKEY: defaultDevice = settings2.value("GU_DefaultDevice").toString(); break; case REMOTE_QRCODE_TYPE: defaultDevice = settings2.value("WC_DefaultDevice").toString(); break; default: defaultDevice = settings2.value("DefaultDevice").toString(); break; } } return defaultDevice; } QStringList ServiceInterface::getAllDefaultDevice(QString userName) { initData(); QStringList listDefDevice; QString configPath = QString(USER_CONFIG_PATH).arg(userName); QSettings settings(configPath, QSettings::IniFormat); int nOldDefType = -1; // 获取用户旧的默认设备 if (settings.contains("DefaultDevice")) { QString strOldDefDev = settings.value("DefaultDevice").toString(); if (!strOldDefDev.isEmpty()) { for (auto devInfo : m_listDeviceInfos) { if (devInfo && devInfo->device_shortname == strOldDefDev) { QString strBioDefType = ""; switch (devInfo->biotype) { case BIOTYPE_FINGERPRINT: strBioDefType = "FP_DefaultDevice"; break; case BIOTYPE_FINGERVEIN: strBioDefType = "FV_DefaultDevice"; break; case BIOTYPE_IRIS: strBioDefType = "IR_DefaultDevice"; break; case BIOTYPE_FACE: strBioDefType = "FC_DefaultDevice"; break; case BIOTYPE_VOICEPRINT: strBioDefType = "VP_DefaultDevice"; break; case UNIT_GENERAL_UKEY: strBioDefType = "GU_DefaultDevice"; break; case REMOTE_QRCODE_TYPE: strBioDefType = "WC_DefaultDevice"; break; default: break; } if (!strBioDefType.isEmpty() && !settings.contains(strBioDefType)) { nOldDefType = devInfo->biotype; listDefDevice.push_back(strOldDefDev); settings.setValue(strBioDefType, strOldDefDev); settings.setValue("DefaultDevice", ""); settings.sync(); } break; } } } } QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat); for (int nBioType = 0; nBioType <= REMOTE_QRCODE_TYPE; nBioType++) { QString defaultDevice = ""; if (nBioType == nOldDefType) continue; switch (nBioType) { case BIOTYPE_FACE: defaultDevice = settings.value("FC_DefaultDevice").toString(); break; case BIOTYPE_FINGERPRINT: defaultDevice = settings.value("FP_DefaultDevice").toString(); break; case BIOTYPE_FINGERVEIN: defaultDevice = settings.value("FV_DefaultDevice").toString(); break; case BIOTYPE_IRIS: defaultDevice = settings.value("IR_DefaultDevice").toString(); break; case BIOTYPE_VOICEPRINT: defaultDevice = settings.value("VP_DefaultDevice").toString(); break; case UNIT_GENERAL_UKEY: defaultDevice = settings.value("GU_DefaultDevice").toString(); break; case REMOTE_QRCODE_TYPE: defaultDevice = settings.value("WC_DefaultDevice").toString(); break; default: break; } if (defaultDevice.isEmpty()) { switch (nBioType) { case BIOTYPE_FACE: defaultDevice = settings2.value("FC_DefaultDevice").toString(); break; case BIOTYPE_FINGERPRINT: defaultDevice = settings2.value("FP_DefaultDevice").toString(); break; case BIOTYPE_FINGERVEIN: defaultDevice = settings2.value("FV_DefaultDevice").toString(); break; case BIOTYPE_IRIS: defaultDevice = settings2.value("IR_DefaultDevice").toString(); break; case BIOTYPE_VOICEPRINT: defaultDevice = settings2.value("VP_DefaultDevice").toString(); break; case UNIT_GENERAL_UKEY: defaultDevice = settings2.value("GU_DefaultDevice").toString(); break; case REMOTE_QRCODE_TYPE: defaultDevice = settings2.value("WC_DefaultDevice").toString(); break; default: break; } } if (!defaultDevice.isEmpty()) { listDefDevice.push_back(defaultDevice); } } return listDefDevice; } // 设置通用默认设备 void ServiceInterface::setCommDefaultDevice(int bioDevType, QString deviceName) { initData(); QSettings settings(COMM_CONFIG_PATH, QSettings::IniFormat); switch (bioDevType) { case BIOTYPE_FACE: settings.setValue("FC_DefaultDevice", deviceName); break; case BIOTYPE_FINGERPRINT: settings.setValue("FP_DefaultDevice", deviceName); break; case BIOTYPE_FINGERVEIN: settings.setValue("FV_DefaultDevice", deviceName); break; case BIOTYPE_IRIS: settings.setValue("IR_DefaultDevice", deviceName); break; case BIOTYPE_VOICEPRINT: settings.setValue("VP_DefaultDevice", deviceName); break; case UNIT_GENERAL_UKEY: settings.setValue("GU_DefaultDevice", deviceName); break; case REMOTE_QRCODE_TYPE: settings.setValue("WC_DefaultDevice", deviceName); break; default: break; } settings.sync(); qDebug() << "setCommDefaultDevice:" << bioDevType << "," << deviceName; emit defaultDeviceChanged("", bioDevType, deviceName); } // 获取通用默认设备 QString ServiceInterface::getCommDefaultDevice(int bioDevType) { initData(); QString defaultDevice = ""; QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat); switch (bioDevType) { case BIOTYPE_FACE: defaultDevice = settings2.value("FC_DefaultDevice").toString(); break; case BIOTYPE_FINGERPRINT: defaultDevice = settings2.value("FP_DefaultDevice").toString(); break; case BIOTYPE_FINGERVEIN: defaultDevice = settings2.value("FV_DefaultDevice").toString(); break; case BIOTYPE_IRIS: defaultDevice = settings2.value("IR_DefaultDevice").toString(); break; case BIOTYPE_VOICEPRINT: defaultDevice = settings2.value("VP_DefaultDevice").toString(); break; case UNIT_GENERAL_UKEY: defaultDevice = settings2.value("GU_DefaultDevice").toString(); break; case REMOTE_QRCODE_TYPE: defaultDevice = settings2.value("WC_DefaultDevice").toString(); break; default: defaultDevice = settings2.value("DefaultDevice").toString(); break; } return defaultDevice; } void ServiceInterface::setBioAuthStatus(int bioAuthType, bool status) { QDBusConnection conn = connection(); QDBusMessage msg = message(); int uid = conn.interface()->serviceUid(msg.service()).value(); struct passwd *pwinfo = getpwuid(uid); if (pwinfo && pwinfo->pw_name) { QString configPath = QString(USER_CONFIG_PATH).arg(pwinfo->pw_name); QSettings settings(configPath, QSettings::IniFormat); switch (bioAuthType) { case ENABLETYPE_BIO: settings.setValue("EnableAuth", status); break; case ENABLETYPE_SAVER: settings.setValue("SaverEnable", status); break; case ENABLETYPE_GREETER: settings.setValue("GreeterEnable", status); break; case ENABLETYPE_POLKIT: settings.setValue("PolkitEnable", status); break; case ENABLETYPE_SU: settings.setValue("SuEnable", status); break; case ENABLETYPE_SUDO: settings.setValue("SudoEnable", status); break; case ENABLETYPE_LOGIN: settings.setValue("LoginEnable", status); break; default: break; } settings.sync(); emit bioAuthStatusChanged(pwinfo->pw_name, bioAuthType, status); qDebug() << "setBioAuthStatus:" << pwinfo->pw_name << "," << bioAuthType << "," << status; } else { qInfo() << "GetPWInfo failed!!"; } } bool ServiceInterface::getBioAuthStatus(QString userName, int bioAuthType) { initData(); QString configPath = QString(USER_CONFIG_PATH).arg(userName); QSettings settings(configPath, QSettings::IniFormat); QString strBioAuthType = ""; switch (bioAuthType) { case ENABLETYPE_BIO: strBioAuthType = "EnableAuth"; break; case ENABLETYPE_SAVER: strBioAuthType = "SaverEnable"; break; case ENABLETYPE_GREETER: strBioAuthType = "GreeterEnable"; break; case ENABLETYPE_POLKIT: strBioAuthType = "PolkitEnable"; break; case ENABLETYPE_SU: strBioAuthType = "SuEnable"; break; case ENABLETYPE_SUDO: strBioAuthType = "SudoEnable"; break; case ENABLETYPE_LOGIN: strBioAuthType = "LoginEnable"; break; default: return false; } // 同步990旧的配置文件,然后删除 if (getIs990() && (bioAuthType == ENABLETYPE_BIO)) { QString oldConfigPath = QString(OLD_990_USER_CONFIG_PATH).arg(userName); QSettings oldSettings(oldConfigPath, QSettings::IniFormat); if (oldSettings.contains(strBioAuthType)) { settings.setValue(strBioAuthType, oldSettings.value(strBioAuthType).toBool()); oldSettings.remove(strBioAuthType); oldSettings.sync(); } } if (settings.contains(strBioAuthType)) { return settings.value(strBioAuthType).toBool(); } else if (getIs990() && (bioAuthType == ENABLETYPE_BIO)) { // 990默认为打开 return true; } else { QSettings settings2(COMM_CONFIG_PATH, QSettings::IniFormat); if (settings2.contains(strBioAuthType)) { return settings2.value(strBioAuthType).toBool(); } else { return true; } } } int ServiceInterface::getMaxFailedTimes() { QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("MaxFailedTimes")) return sysSettings.value("MaxFailedTimes").toInt(); else return 3; } int ServiceInterface::getFTimeoutTimes() { QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("FaceTimeoutTimes")) return sysSettings.value("FaceTimeoutTimes").toInt(); else return 1; } void ServiceInterface::setFTimeoutTimes(int times) { if (times < 1) times = 1; QSettings settings(COMM_CONFIG_PATH, QSettings::IniFormat); settings.setValue("FaceTimeoutTimes", times); } bool ServiceInterface::getQRCodeEnable() { bool isEnable = false; QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); sysSettings.beginGroup("Functions"); if (sysSettings.allKeys().contains("EnableQRCode")) { isEnable = sysSettings.value("EnableQRCode").toBool(); } sysSettings.endGroup(); return isEnable; } // 获取是否双认证 bool ServiceInterface::getDoubleAuth() { QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("DoubleAuth")) return sysSettings.value("DoubleAuth").toBool(); else return false; } // 获取用户绑定 bool ServiceInterface::getUserBind() { QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("UserBind")) return sysSettings.value("UserBind").toBool(); else return false; } // 获取是否在控制面板显示 bool ServiceInterface::getIsShownInControlCenter() { QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("isShownInControlCenter")) return sysSettings.value("isShownInControlCenter").toBool(); else return false; } // 获取是否使用第一个设备 bool ServiceInterface::getUseFirstDevice() { QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("UseFirstDevice")) return sysSettings.value("UseFirstDevice").toBool(); else return false; } // 获取是否隐藏切换按钮 bool ServiceInterface::getHiddenSwitchButton() { QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("HiddenSwitchButton")) return sysSettings.value("HiddenSwitchButton").toBool(); else return false; } // 获取旧版app使能值 int ServiceInterface::getOldAppStatus() { initData(); QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("EnableAuthApp")) return sysSettings.value("EnableAuthApp").toInt(); else return 63; } void ServiceInterface::onUSBDeviceHotPlug(int drvid, int action, int deviceNum) { if (action > 0) { qDebug() << "onUSBDeviceHotPlug in:" << drvid; updateCommDefaultDevice(drvid); } } // 记录当前生物认证信息 void ServiceInterface::recordAuthDrive(QString appName, int drvid, bool insert) { if (insert) { m_AuthingDriveList.insert(appName, drvid); } else { m_AuthingDriveList.remove(appName); } } // 获取当前正在认证的应用 QStringList ServiceInterface::getAllAuthApp() { return m_AuthingDriveList.keys(); } // 根据应用名称获取认证的驱动 int ServiceInterface::getAppAuthDrive(QString appName) { if (m_AuthingDriveList.contains(appName)) { return m_AuthingDriveList.value(appName); } return -1; } QString ServiceInterface::GetUserInformation(QString username) { KyInfo() << username; return KYLINUSERDATAMNG::getInstance()->GetConfInformation(username); } void ServiceInterface::SetLoginSynInformation(QString val) { KyInfo() << val; KYLINUSERDATAMNG::getInstance()->SetLoginSynInformation(val); } void ServiceInterface::waitBiometricServiceStatus() { qDebug() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~` get biometric status"; QDBusInterface iface( "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", QDBusConnection::systemBus()); QDBusReply bioPath = iface.call("GetUnit", "biometric-authentication.service"); if (!bioPath.isValid()) { return; } QDBusInterface bioface( "org.freedesktop.systemd1", bioPath.value().path(), "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusReply sessionReply = bioface.call("Get", "org.freedesktop.systemd1.Unit", "UnitFileState"); if (!sessionReply.isValid()) qWarning() << sessionReply.error(); else { QString res = sessionReply.value().variant().toString(); if (res == "disable") return; } qDebug() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ get activeState"; int times = 0; while (times < 20) { QDBusReply sessionReply = bioface.call("Get", "org.freedesktop.systemd1.Unit", "ActiveState"); if (!sessionReply.isValid()) { qWarning() << sessionReply.error(); return; } else { QString res = sessionReply.value().variant().toString(); if (res == "activating") { times++; usleep(100000); } else { break; } } } qDebug() << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ times = " << times; } void ServiceInterface::updateCommDefaultDevice(int nDriId) { if (!m_serviceInterface) { return; } QVariant variant; QDBusArgument argument; QList qlist; QDBusVariant item; DeviceInfoPtr deviceInfo = nullptr; /* 返回值为 i -- int 和 av -- array of variant */ QDBusPendingReply> reply = m_serviceInterface->call("GetDrvList"); reply.waitForFinished(); if (reply.isError()) { qDebug() << "GUI:" << reply.error(); deviceCount = 0; return; } /* 解析 DBus 返回值,reply 有两个返回值,都是 QVariant 类型 */ variant = reply.argumentAt(0); /* 得到第一个返回值 */ deviceCount = variant.value(); /* 解封装得到设备个数 */ variant = reply.argumentAt(1); /* 得到第二个返回值 */ argument = variant.value(); /* 解封装,获取QDBusArgument对象 */ argument >> qlist; /* 使用运算符重载提取 argument 对象里面存储的列表对象 */ if (nDriId != -1) { // 指定设备接入 for (int i = 0; i < deviceCount; i++) { item = qlist[i]; /* 取出一个元素 */ variant = item.variant(); /* 转为普通QVariant对象 */ /* 解封装得到 QDBusArgument 对象 */ argument = variant.value(); deviceInfo = std::make_shared(); argument >> *deviceInfo; /* 提取最终的 DeviceInfo 结构体 */ if (nDriId == deviceInfo->device_id) { if (getCommDefaultDevice(deviceInfo->biotype).isEmpty()) { setCommDefaultDevice(deviceInfo->biotype, deviceInfo->device_shortname); } break; } } } else { m_listDeviceInfos.clear(); for (int i = 0; i < deviceCount; i++) { item = qlist[i]; /* 取出一个元素 */ variant = item.variant(); /* 转为普通QVariant对象 */ /* 解封装得到 QDBusArgument 对象 */ argument = variant.value(); deviceInfo = std::make_shared(); argument >> *deviceInfo; /* 提取最终的 DeviceInfo 结构体 */ m_listDeviceInfos.push_back(deviceInfo); } } } void ServiceInterface::initData() { if (m_isDataInited) { return; } updateCommDefaultDevice(-1); // 沿用旧app enable QSettings sysSettings(COMM_CONFIG_PATH, QSettings::IniFormat); if (sysSettings.contains("EnableAuthApp") || sysSettings.contains("Functions/EnableAuthApp")) { int nAppOldStatus = 0; if (sysSettings.contains("Functions/EnableAuthApp")) { nAppOldStatus = sysSettings.value("Functions/EnableAuthApp").toInt(); } else { nAppOldStatus = sysSettings.value("EnableAuthApp").toInt(); } if ((nAppOldStatus & 0x01) && !sysSettings.contains("GreeterEnable")) { // greeter sysSettings.setValue("GreeterEnable", true); } if ((nAppOldStatus & 0x02) && !sysSettings.contains("SaverEnable")) { // saver sysSettings.setValue("SaverEnable", true); } if ((nAppOldStatus & 0x04) && !sysSettings.contains("PolkitEnable")) { // polkit sysSettings.setValue("PolkitEnable", true); } if ((nAppOldStatus & 0x08) && !sysSettings.contains("SudoEnable")) { // sudo sysSettings.setValue("SudoEnable", true); } if ((nAppOldStatus & 0x10) && !sysSettings.contains("SuEnable")) { // su sysSettings.setValue("SuEnable", true); } if ((nAppOldStatus & 0x20) && !sysSettings.contains("LoginEnable")) { // login sysSettings.setValue("LoginEnable", true); } } // 沿用旧的默认设备 if (sysSettings.contains("DefaultDevice")) { QString strOldDefDev = sysSettings.value("DefaultDevice").toString(); if (!strOldDefDev.isEmpty()) { for (auto devInfo : m_listDeviceInfos) { if (devInfo && devInfo->device_shortname == strOldDefDev) { QString strBioDefType = ""; switch (devInfo->biotype) { case BIOTYPE_FINGERPRINT: strBioDefType = "FP_DefaultDevice"; break; case BIOTYPE_FINGERVEIN: strBioDefType = "FV_DefaultDevice"; break; case BIOTYPE_IRIS: strBioDefType = "IR_DefaultDevice"; break; case BIOTYPE_FACE: strBioDefType = "FC_DefaultDevice"; break; case BIOTYPE_VOICEPRINT: strBioDefType = "VP_DefaultDevice"; break; case UNIT_GENERAL_UKEY: strBioDefType = "GU_DefaultDevice"; break; case REMOTE_QRCODE_TYPE: strBioDefType = "WC_DefaultDevice"; break; default: break; } if (!strBioDefType.isEmpty() && !sysSettings.contains(strBioDefType)) { sysSettings.setValue(strBioDefType, strOldDefDev); sysSettings.setValue("DefaultDevice", ""); } break; } } } } // 设置未设置过默认设备的类型,如果驱动已打开且已连接 for (auto devInfo : m_listDeviceInfos) { if (devInfo && devInfo->device_available > 0 && devInfo->driver_enable > 0) { QString strBioDefType = ""; switch (devInfo->biotype) { case BIOTYPE_FINGERPRINT: strBioDefType = "FP_DefaultDevice"; break; case BIOTYPE_FINGERVEIN: strBioDefType = "FV_DefaultDevice"; break; case BIOTYPE_IRIS: strBioDefType = "IR_DefaultDevice"; break; case BIOTYPE_FACE: strBioDefType = "FC_DefaultDevice"; break; case BIOTYPE_VOICEPRINT: strBioDefType = "VP_DefaultDevice"; break; case UNIT_GENERAL_UKEY: strBioDefType = "GU_DefaultDevice"; break; case REMOTE_QRCODE_TYPE: strBioDefType = "WC_DefaultDevice"; break; default: break; } if (!strBioDefType.isEmpty() && !sysSettings.contains(strBioDefType)) { sysSettings.setValue(strBioDefType, devInfo->device_shortname); } } } sysSettings.sync(); m_isDataInited = true; } void ServiceInterface::onBiometricDbusChanged(bool bActive) { qDebug() << "BiometricDbus:" << bActive; if (bActive) { updateCommDefaultDevice(-1); initData(); } } void ServiceInterface::checkIs990() { #if QT_VERSION_MAJOR == 6 QRegularExpression r1("kirin.*9.0", QRegularExpression::CaseInsensitiveOption); QRegularExpression r2("pangu.*m900", QRegularExpression::CaseInsensitiveOption); #else QRegExp r1("kirin.*9.0"); r1.setCaseSensitivity(Qt::CaseInsensitive); QRegExp r2("pangu.*m900"); r2.setCaseSensitivity(Qt::CaseInsensitive); #endif QFile file(PROC_CPUINFO); if (!file.exists()) { is990 = false; } file.open(QFile::ReadOnly); QString str(file.readAll()); #if QT_VERSION_MAJOR == 6 is990 = (r1.match(str).hasMatch() || r2.match(str).hasMatch()); #else is990 = (str.contains(r1) || str.contains(r2)); #endif file.close(); } bool ServiceInterface::getIs990() { return is990; } QString ServiceInterface::getPublicEncrypt() { if (pubKey.isEmpty()) { rsac.generateKeyPair(priKey, pubKey, 1024); } return pubKey; } bool ServiceInterface::sendPassword(QString username, QByteArray password) { if (priKey.isEmpty()) { rsac.generateKeyPair(priKey, pubKey, 1024); } QByteArray decryptText; QByteArray encryptText; rsac.decrypt(password, decryptText, priKey); // 解密 // 如果处于登录状态 qDebug() << "sendPassword" << loginAppList.count() << loginAppList; if (loginAppList.contains("lightdm")) { qDebug() << "login:"; isFirstLogin = false; QString publicKey = getLoginPubKey(loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE); rsac.encrypt(decryptText, encryptText, publicKey.toLatin1()); return sendLoginPassword( loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, username, encryptText); } // 处于锁屏状态 if (loginAppList.contains(username)) { qDebug() << "unlock:"; isFirstLogin = false; QString publicKey = getLoginPubKey(loginAppList.value(username), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE); rsac.encrypt(decryptText, encryptText, publicKey.toLatin1()); return sendLoginPassword( loginAppList.value(username), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, username, encryptText); } if (loginAppList.count() > 0) { qDebug() << "login by screensaver:"; isFirstLogin = false; QString publicKey = getLoginPubKey( loginAppList.value(loginAppList.firstKey()), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE); rsac.encrypt(decryptText, encryptText, publicKey.toLatin1()); return sendLoginPassword( loginAppList.value(loginAppList.firstKey()), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, username, encryptText); } // 如果是第一次调用,则配置自动登录 if (isFirstLogin) { qDebug() << "isFirstLogin:"; isFirstLogin = false; hasSaveLogin = true; return handleFirstSingleLogn(username, decryptText); } isFirstLogin = false; return false; } bool ServiceInterface::handleFirstSingleLogn(QString username, QByteArray decryptText) { QEventLoop loopTemp; bool ret = false; QByteArray encryptText; qDebug() << "handleFirstSingleLogn wait"; QMetaObject::Connection connection = QObject::connect(this, &ServiceInterface::onLoginServicdRegisted, [&loopTemp]() { if (loopTemp.isRunning()) { loopTemp.quit(); } }); QTimer::singleShot(10000, &loopTemp, SLOT(quit())); loopTemp.exec(); qDebug() << "handleFirstSingleLogn finished"; disconnect(connection); qDebug() << loginAppList.count(); if (loginAppList.contains("lightdm")) { isFirstLogin = false; QString publicKey = getLoginPubKey(loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE); if (publicKey.isEmpty()) { qDebug() << "get Login PubKey failed!"; return false; } rsac.encrypt(decryptText, encryptText, publicKey.toLatin1()); return sendLoginPassword( loginAppList.value("lightdm"), SCREENSAVER_DBUS_PATH, SCREENSAVER_DBUS_INTERFACE, username, encryptText); } return ret; } QString ServiceInterface::getLoginPubKey(QString service, QString path, QString interface) { QDBusInterface iface(service, path, interface, QDBusConnection::systemBus()); QDBusReply stateReply = iface.call("getPublicEncrypt"); if (!stateReply.isValid()) { qWarning() << "Get state error:" << stateReply.error(); qDebug() << "getPublicEncrypt failed"; return ""; } return stateReply.value(); } bool ServiceInterface::sendSignalLoginFinished(QString username, bool res) { qDebug() << "sendSignalLoginFinished " << username << res; emit onSignalLoginFinished(username, res); return true; } bool ServiceInterface::sendLoginPassword( QString service, QString path, QString interface, QString username, QByteArray array) { QEventLoop loopTemp; bool ret = false; qDebug() << "sendLoginPassword"; QMetaObject::Connection connection = QObject::connect( this, &ServiceInterface::onSignalLoginFinished, [&loopTemp, &ret](QString username, bool res) { qDebug() << "onSignalLoginFinished:" << username << res; ret = res; if (loopTemp.isRunning()) { loopTemp.quit(); } }); QDBusInterface iface(service, path, interface, QDBusConnection::systemBus()); QDBusReply stateReply = iface.call("sendPassword", username, array); if (!stateReply.isValid()) { disconnect(connection); return false; } if (!stateReply.value()) { disconnect(connection); return stateReply.value(); } QTimer::singleShot(30000, &loopTemp, SLOT(quit())); loopTemp.exec(); disconnect(connection); return ret; } QString ServiceInterface::getProcessNameFromPid(int pid) { QString filename = "/proc/" + QString::number(pid) + "/cmdline"; qDebug() << "filename is " << filename; QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Can't open the file!"; return ""; } QByteArray text = file.readAll(); return QString(text); } QString ServiceInterface::getUserNameFromUid(int uid) { struct passwd *pw = NULL; pw = getpwuid(uid); if (pw) { return QString(pw->pw_name); } return ""; } void ServiceInterface::onDbusNameOwnerChanged(QString name, QString oldOwner, QString newOwner) { if (newOwner.isEmpty()) { for (QString str : loginAppList.keys()) { if (name == loginAppList.value(str)) { qDebug() << "remove name " << name; loginAppList.remove(str); } } } } bool ServiceInterface::registerLoginApp() { QDBusConnection conn = connection(); QDBusMessage msg = message(); qDebug() << "Sender Name" << conn.interface()->serviceOwner(msg.service()).value(); qDebug() << "Sender Pid " << conn.interface()->servicePid(msg.service()).value(); qDebug() << "Sender uid " << conn.interface()->serviceUid(msg.service()).value(); int pid = conn.interface()->servicePid(msg.service()).value(); QString serviceOwner = conn.interface()->serviceOwner(msg.service()).value(); int uid = conn.interface()->serviceUid(msg.service()).value(); QString appName = getProcessNameFromPid(pid); qDebug() << "appName = " << appName; if (appName != UKUI_GREETER && appName != UKUI_SCREENSAVER) { return false; } QString appUser = getUserNameFromUid(uid); if (appUser.isEmpty()) return false; qDebug() << "insert " << appUser << serviceOwner; loginAppList.insert(appUser, serviceOwner); if (appUser == "lightdm" && hasSaveLogin) { QTimer::singleShot(1000, this, [=]() { emit onLoginServicdRegisted(); }); } return true; } int ServiceInterface::SwitchToUser(QString strUserName) { m_willLoginUser.strUserName = strUserName; m_willLoginUser.isOneKeyLogin = true; Q_EMIT userChanged(m_willLoginUser); return 0; } int ServiceInterface::SwitchToGreeterUser(QString strUserName) { m_willLoginUser.strUserName = strUserName; m_willLoginUser.isOneKeyLogin = false; Q_EMIT userChanged(m_willLoginUser); return 0; } WillLoginUserInfo ServiceInterface::getWillSwitchUser() { return m_willLoginUser; } int ServiceInterface::SaveLastLoginUser(QString strUserName) { QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat); settings.beginGroup("Greeter"); settings.setValue("lastLoginUser", strUserName); settings.endGroup(); settings.sync(); return 0; } QString ServiceInterface::GetLastLoginUser() { QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat); settings.beginGroup("Greeter"); QString lastLoginUser = settings.value("lastLoginUser").toString(); settings.endGroup(); return lastLoginUser; } int ServiceInterface::SaveQuickLoginUser(QString strUserName) { QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat); settings.beginGroup("Greeter"); settings.setValue("lastLoginUser1", strUserName); settings.endGroup(); settings.sync(); return 0; } QString ServiceInterface::GetQuickLoginUser() { QSettings settings(LAST_LOGIN_INFO_PATH, QSettings::IniFormat); settings.beginGroup("Greeter"); QString lastLoginUser = settings.value("lastLoginUser1").toString(); settings.endGroup(); return lastLoginUser; } ukui-biometric-auth/uniauth-backend/src/greeterconfig.cpp0000664000175000017500000002200715167732644022567 0ustar fengfeng/* * Copyright (C) 2024 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "greeterconfig.h" #include #include #include #include #include #include #include #define GREETER_CONFIG_DEFAULT_FILE "/var/cache/ukui-greeter/default.conf" #define GREETER_CONFIG_CUSTOM_FILE "/var/cache/ukui-greeter/custom.conf" #define GREETER_CONFIG_ETC_DIR "/etc/ukui/ukui-greeter/ukui-greeter.conf.d/" #define GREETER_CONFIG_ETC_FILE "/etc/ukui/ukui-greeter/ukui-greeter.conf" #define GREETER_CONFIG_USER_FILE "%1/.config/ukui-greeter/ukui-greeter.conf" GreeterConfig::GreeterConfig(QObject *parent) : QObject(parent), m_setttingsDefault(nullptr), m_settingsCustom(nullptr) { initData(); } void GreeterConfig::initData() { m_strHomePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); if (!m_setttingsDefault) { m_setttingsDefault = new QSettings(GREETER_CONFIG_DEFAULT_FILE, QSettings::IniFormat, this); m_setttingsDefault->clear(); } // read config from conf.d directory loadConfigDirectory(GREETER_CONFIG_ETC_DIR); // read config from conf file loadConfigFromFile(GREETER_CONFIG_ETC_FILE); if (!m_settingsCustom) { m_settingsCustom = new QSettings(GREETER_CONFIG_CUSTOM_FILE, QSettings::IniFormat, this); } } void GreeterConfig::loadConfigDirectory(QString strPath) { QDir confDir(strPath); QStringList filePathList = confDir.entryList(QDir::Files, QDir::Name); for (const QString &filePath : filePathList) { if (filePath.endsWith(".conf")) { loadConfigFromFile(strPath + filePath); } } if (m_setttingsDefault) { m_setttingsDefault->sync(); } } void GreeterConfig::loadConfigFromFile(QString strPath) { if (!m_setttingsDefault) { return; } qDebug() << "conf file:" << strPath; QSettings *settingsConf = new QSettings(strPath, QSettings::IniFormat, this); QStringList groups = settingsConf->childGroups(); foreach (const QString &group, groups) { settingsConf->beginGroup(group); QStringList keys = settingsConf->childKeys(); foreach (const QString &key, keys) { m_setttingsDefault->beginGroup(group); m_setttingsDefault->setValue(key, settingsConf->value(key)); m_setttingsDefault->endGroup(); } settingsConf->endGroup(); } settingsConf->deleteLater(); settingsConf = nullptr; } void GreeterConfig::setValue( const QString &group, const QString &key, const QVariant &value, QString strUserName /* = ""*/) { if ((strUserName.isEmpty() && !m_settingsCustom) || group.isEmpty() || key.isEmpty()) { return; } if (!strUserName.isEmpty()) { QString strHomePath = getUserHomePath(strUserName); if (strHomePath.isEmpty()) { qDebug() << "GetUserHomePath failed!"; return; } QSettings userSettings(QString(GREETER_CONFIG_USER_FILE).arg(strHomePath), QSettings::IniFormat); userSettings.beginGroup(group); userSettings.setValue(key, value); userSettings.endGroup(); userSettings.sync(); Q_EMIT changedForUser(group, key, strUserName); } else if (m_settingsCustom) { m_settingsCustom->beginGroup(group); m_settingsCustom->setValue(key, value); m_settingsCustom->endGroup(); m_settingsCustom->sync(); Q_EMIT changed(group, key); } } QVariant GreeterConfig::getValue(const QString &group, const QString &key, QVariant varDefault, QString strUserName /*= ""*/) { QVariant varValue; if (!strUserName.isEmpty()) { QString strHomePath = getUserHomePath(strUserName); if (!strHomePath.isEmpty()) { QSettings userSettings(QString(GREETER_CONFIG_USER_FILE).arg(strHomePath), QSettings::IniFormat); if (userSettings.contains(group + "/" + key)) { userSettings.beginGroup(group); varValue = userSettings.value(key); userSettings.endGroup(); return varValue; } } } if (m_settingsCustom) { if (m_settingsCustom->contains(group + "/" + key)) { m_settingsCustom->beginGroup(group); varValue = m_settingsCustom->value(key); m_settingsCustom->endGroup(); return varValue; } } if (m_setttingsDefault) { if (m_setttingsDefault->contains(group + "/" + key)) { m_setttingsDefault->beginGroup(group); varValue = m_setttingsDefault->value(key); m_setttingsDefault->endGroup(); return varValue; } } return varDefault; } bool GreeterConfig::resetValue(const QString &group, const QString &key, QString strUserName /*= ""*/) { bool bRet = false; if (!strUserName.isEmpty()) { QString strHomePath = getUserHomePath(strUserName); if (!strHomePath.isEmpty()) { QSettings userSettings(QString(GREETER_CONFIG_USER_FILE).arg(strHomePath), QSettings::IniFormat); if (userSettings.contains(group + "/" + key)) { userSettings.beginGroup(group); userSettings.remove(key); userSettings.endGroup(); Q_EMIT changedForUser(group, key, strUserName); bRet = true; } } } if (m_settingsCustom) { if (m_settingsCustom->contains(group + "/" + key)) { m_settingsCustom->beginGroup(group); m_settingsCustom->remove(key); m_settingsCustom->endGroup(); Q_EMIT changed(group, key); bRet = true; } } return bRet; } QString GreeterConfig::printConfig(int nType, QString strUserName /*= ""*/) { // 创建一个空的QJsonObject QJsonObject jsonObject; switch (nType) { case 2: { if (m_settingsCustom) { QStringList keys = m_settingsCustom->allKeys(); for (const QString &key : keys) { jsonObject[key] = m_settingsCustom->value(key).toString(); } } if (!strUserName.isEmpty()) { QString strHomePath = getUserHomePath(strUserName); if (!strHomePath.isEmpty()) { QSettings userSettings(QString(GREETER_CONFIG_USER_FILE).arg(strHomePath), QSettings::IniFormat); QStringList keys = userSettings.allKeys(); for (const QString &key : keys) { jsonObject[key] = userSettings.value(key).toString(); } } } } break; case 1: { if (m_setttingsDefault) { QStringList keys = m_setttingsDefault->allKeys(); for (const QString &key : keys) { jsonObject[key] = m_setttingsDefault->value(key).toString(); } } } break; case 0: default: { if (m_setttingsDefault) { QStringList keys = m_setttingsDefault->allKeys(); for (const QString &key : keys) { jsonObject[key] = m_setttingsDefault->value(key).toString(); } } if (m_settingsCustom) { QStringList keys = m_settingsCustom->allKeys(); for (const QString &key : keys) { jsonObject[key] = m_settingsCustom->value(key).toString(); } } if (!strUserName.isEmpty()) { QString strHomePath = getUserHomePath(strUserName); if (!strHomePath.isEmpty()) { QSettings userSettings(QString(GREETER_CONFIG_USER_FILE).arg(strHomePath), QSettings::IniFormat); QStringList keys = userSettings.allKeys(); for (const QString &key : keys) { jsonObject[key] = userSettings.value(key).toString(); } } } } break; } // 创建QJsonDocument QJsonDocument jsonDoc(jsonObject); return jsonDoc.toJson(); } QString GreeterConfig::getUserHomePath(const QString &strUserName) { if (strUserName.isEmpty()) { return QString(""); } struct passwd *pwdInfo = getpwnam(strUserName.toLatin1().data()); if (pwdInfo) { return QString(pwdInfo->pw_dir); } return QString(""); } ukui-biometric-auth/uniauth-backend/org.ukui.UniauthBackend.yaml0000664000175000017500000000160115167732644023761 0ustar fengfengorg:ukui:UniauthBackend: 1.0.0.1: audit: _type: b _default: false whitelist: _type: as _default: '["/usr/sbin/ukui-greeter","/usr/bin/ukui-screensaver-backend","/usr/bin/ukui-screensaver-dialog","/usr/sbin/lightdm","/usr/bin/ukui-control-center","/usr/bin/ukui-session-tools","/usr/bin/ukui-session","/usr/lib/x86_64-linux-gnu/ukui-polkit/polkit-ukui-authentication-agent-1","/usr/lib/aarch64-linux-gnu/ukui-polkit/polkit-ukui-authentication-agent-1","/usr/lib/loongarch64-linux-gnu/ukui-polkit/polkit-ukui-authentication-agent-1","/usr/lib/mips64el-linux-gnu/ukui-polkit/polkit-ukui-authentication-agent-1","/usr/lib/sw_64-linux-gnu/ukui-polkit/polkit-ukui-authentication-agent-1","/usr/bin/bioauth","/usr/bin/biometric-manager","/usr/bin/ukui-biometric-manager","/usr/sbin/box-manager","/usr/share/kare/plugins/kare-polkit/polkit-kare-authentication-agent-1"]' ukui-biometric-auth/uniauth-backend/org.ukui.UniauthBackend.conf0000664000175000017500000000156515167732631023751 0ustar fengfeng ukui-biometric-auth/uniauth-backend/CMakeLists.txt0000664000175000017500000000253415167732644021214 0ustar fengfengproject(uniauth-backend) set(CMAKE_AUTOMOC ON) # 定义源文件 set(bin_SRCS src/main.cpp src/biodeviceinfo.h src/biodeviceinfo.cpp src/serviceinterface.h src/serviceinterface.cpp src/servicemanager.h src/servicemanager.cpp src/personalizeddata.h src/CSingleton.h src/personalizeddata.cpp src/rsac.h src/rsac.cpp src/greeterconfiginterface.h src/greeterconfiginterface.cpp src/greeterconfig.h src/greeterconfig.cpp ) # 根据Qt版本设置包含目录和链接库 if(QT_VERSION_MAJOR EQUAL 6) include_directories( ${Qt6Core_INCLUDE_DIRS} ${Qt6DBus_INCLUDE_DIRS} ) add_executable(uniauth-backend ${bin_SRCS}) target_link_libraries(uniauth-backend Qt6::Core Qt6::DBus -lukui-log4qt -lcrypto) else() include_directories( ${Qt5Core_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS} ) add_executable(uniauth-backend ${bin_SRCS}) target_link_libraries(uniauth-backend Qt5::Core Qt5::DBus -lukui-log4qt -lcrypto) endif() install(TARGETS uniauth-backend DESTINATION bin) install(FILES org.ukui.UniauthBackend.conf DESTINATION /usr/share/dbus-1/system.d/) install(FILES org.ukui.UniauthBackend.service DESTINATION /usr/share/dbus-1/system-services/) install(FILES org.ukui.UniauthBackend.yaml DESTINATION /usr/share/libpam-biometric/kylin-config/) ukui-biometric-auth/uniauth-backend/org.ukui.UniauthBackend.service0000664000175000017500000000012515167732631024453 0ustar fengfeng[D-BUS Service] Name=org.ukui.UniauthBackend Exec=/usr/bin/uniauth-backend User=root ukui-biometric-auth/bioauth/0000775000175000017500000000000015167732644015041 5ustar fengfengukui-biometric-auth/bioauth/src/0000775000175000017500000000000015167732644015630 5ustar fengfengukui-biometric-auth/bioauth/src/uniauthservice.cpp0000664000175000017500000002162515167732630021373 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "uniauthservice.h" #include #include #define UNIAUTH_DBUS_SERVICE "org.ukui.UniauthBackend" #define UNIAUTH_DBUS_PATH "/org/ukui/UniauthBackend" #define UNIAUTH_DBUS_INTERFACE "org.ukui.UniauthBackend" #define FD_DBUS_SERVICE "org.freedesktop.DBus" #define FD_DBUS_PATH "/org/freedesktop/DBus" #define FD_DBUS_INTERFACE "org.freedesktop.DBus" UniAuthService::UniAuthService(QObject *parent) : QDBusAbstractInterface(UNIAUTH_DBUS_SERVICE, UNIAUTH_DBUS_PATH, UNIAUTH_DBUS_INTERFACE, QDBusConnection::systemBus(), parent) , m_isActivatable(false) { setTimeout(2147483647); QDBusInterface *dbusService = new QDBusInterface(FD_DBUS_SERVICE, FD_DBUS_PATH, FD_DBUS_INTERFACE, QDBusConnection::systemBus()); if (dbusService) { QDBusReply result = dbusService->call(QStringLiteral("ListActivatableNames")); if(!result.isValid()) { qWarning() << "ListActivatableNames error:" << result.error().message(); } else { QStringList listNames = result.value(); if (listNames.contains(UNIAUTH_DBUS_INTERFACE)) { m_isActivatable = true; } } } } // 设置默认设备 void UniAuthService::setDefaultDevice(int bioDevType, QString deviceName) { qDebug() << " bioType : " << bioDevType << "deviceName : " << deviceName; QDBusMessage result = call(QStringLiteral("setDefaultDevice"), bioDevType, deviceName); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "setDefaultDevice error:" << result.errorMessage(); return ; } return ; } // 获取默认设备 QString UniAuthService::getDefaultDevice(QString userName, int bioDevType) { QDBusMessage result = call(QStringLiteral("getDefaultDevice"), userName, bioDevType); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getDefaultDevice error:" << result.errorMessage(); return ""; } QList varResult = result.arguments(); if (varResult.size() > 0) { QString strDefDevice = varResult.takeFirst().toString(); return strDefDevice; } else { return ""; } } // 获取所有默认设备 QStringList UniAuthService::getAllDefaultDevice(QString userName) { QStringList listDefDevices; QDBusReply result = call(QStringLiteral("getAllDefaultDevice"), userName); if(!result.isValid()) { qWarning() << "getAllDefaultDevice error:" << result.error().message(); } else { listDefDevices = result.value(); } return listDefDevices; } //生物特征开关接口 bool UniAuthService::getBioAuthStatus(QString userName, int bioAuthType) { QDBusMessage bioResult = call(QStringLiteral("getBioAuthStatus"), userName, bioAuthType); if(bioResult.type() == QDBusMessage::ErrorMessage) { qWarning() << "getBioStatus error:" << bioResult.errorMessage(); return false; } QList varResult = bioResult.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toBool(); } else { return false; } } void UniAuthService::setBioAuthStatus(int bioAuthType, bool status) { qDebug() << "setBioAuthStatus bioAuthType : " << bioAuthType << "status : " << status; QDBusMessage result = call(QStringLiteral("setBioAuthStatus"), bioAuthType, status); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "setBioAuthStatus error:" << result.errorMessage(); return ; } return ; } // 获取最大失败次数 int UniAuthService::getMaxFailedTimes() { QDBusMessage result = call(QStringLiteral("getMaxFailedTimes")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getMaxFailedTimes error:" << result.errorMessage(); return false; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toInt(); } else { return 3; } } // 获取是否使能微信扫码登录 bool UniAuthService::getQRCodeEnable() { QDBusMessage result = call(QStringLiteral("getQRCodeEnable")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getQRCodeEnable error:" << result.errorMessage(); return false; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toBool(); } else { return false; } } // 获取是否双认证 bool UniAuthService::getDoubleAuth() { QDBusMessage result = call(QStringLiteral("getDoubleAuth")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getDoubleAuth error:" << result.errorMessage(); return false; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toBool(); } else { return false; } } // 获取用户绑定 bool UniAuthService::getUserBind() { QDBusMessage result = call(QStringLiteral("getUserBind")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getUserBind error:" << result.errorMessage(); return false; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toBool(); } else { return false; } } // 获取是否在控制面板显示 bool UniAuthService::getIsShownInControlCenter() { QDBusMessage result = call(QStringLiteral("getIsShownInControlCenter")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getIsShownInControlCenter error:" << result.errorMessage(); return false; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toBool(); } else { return false; } } // 获取是否使用第一个设备 bool UniAuthService::getUseFirstDevice() { QDBusMessage result = call(QStringLiteral("getUseFirstDevice")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getUseFirstDevice error:" << result.errorMessage(); return false; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toBool(); } else { return false; } } // 获取是否隐藏切换按钮 bool UniAuthService::getHiddenSwitchButton() { QDBusMessage result = call(QStringLiteral("getHiddenSwitchButton")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getHiddenSwitchButton error:" << result.errorMessage(); return false; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toBool(); } else { return false; } } // 获取正在认证的应用 QStringList UniAuthService::getAuthingApp() { QDBusMessage result = call(QStringLiteral("getAllAuthApp")); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getAuthingApp error:" << result.errorMessage(); return QStringList(); } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toStringList(); } else { return QStringList(); } } // 获取应用认证的驱动 int UniAuthService::getAuthingAppDrivd(QString appName) { QDBusMessage result = call(QStringLiteral("getAppAuthDrive"),appName); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "getAuthingAppDrivd error:" << result.errorMessage(); return -1; } QList varResult = result.arguments(); if (varResult.size() > 0) { return varResult.takeFirst().toInt(); } else { return -1; } } void UniAuthService::recordAuthDrive(QString appName,int drvid,bool insert) { call(QStringLiteral("recordAuthDrive"),appName,drvid,insert); } bool UniAuthService::isActivatable() { return m_isActivatable; } ukui-biometric-auth/bioauth/src/bioauthwidget.cpp0000664000175000017500000001503715167732630021174 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "bioauthwidget.h" #include "ui_bioauthwidget.h" #include #include "generic.h" #include #include #include "giodbus.h" #include #include #include #include #include "biodeviceswidget.h" int BioAuthWidget::failedCount = 0; BioAuthWidget::BioAuthWidget(QWidget *parent) : QWidget(parent), ui(new Ui::BioAuthWidget), bioAuth(nullptr) { nMaxFailCnt = GetFailedTimes(); ui->setupUi(this); ui->btnRetry->setFlat(true); ui->btnRetry->setVisible(false); ui->btnRetry->setText(tr("Retry")); //ui->btnMore->setVisible(false); } BioAuthWidget::~BioAuthWidget() { delete ui; } void BioAuthWidget::emitSwithToPassword() { Q_EMIT switchToPassword(); } void BioAuthWidget::on_btnPasswdAuth_clicked() { stopAuth(); //Q_EMIT switchToPassword(); QTimer::singleShot(100,this,SLOT(emitSwithToPassword())); } void BioAuthWidget::on_btnMore_clicked() { Q_EMIT selectDevice(); } void BioAuthWidget::on_btnRetry_clicked() { if(bioAuth && !bioAuth->isAuthenticating()) { setMovie(); bioAuth->startAuth(); } } void BioAuthWidget::onBioAuthNotify(const QString ¬ifyMsg) { ui->lblBioNotify->setText(notifyMsg); } void BioAuthWidget::onBioAuthComplete(uid_t uid, bool ret, int retErrNo) { if (!device) return ; if (ret == true) { BioAuthWidget::failedCount = 0; }else{ BioAuthWidget::failedCount++; } setImage(); dup_fd = -1; if(BioAuthWidget::failedCount >= nMaxFailCnt) { // ui->lblBioWarnNotify->setText(tr("Too many unsuccessful attempts,please enter password.")); ui->lblBioWarnNotify->setText(tr("%1 too many unsuccessful attempts,please enter password.").arg(BioDevices::bioTypeToString_tr(device->biotype))); } else { ui->btnRetry->setVisible(true); // ui->lblBioWarnNotify->setText(tr("Authentication failure,there are still %1 remaining opportunities").arg(nMaxFailCnt - BioAuthWidget::failedCount)); ui->lblBioWarnNotify->setText(tr("%1 authentication failure,there are still %2 remaining opportunities").arg(BioDevices::bioTypeToString_tr(device->biotype)).arg(nMaxFailCnt - BioAuthWidget::failedCount)); } Q_EMIT authComplete(uid, ret); } void BioAuthWidget::setMovie() { if(!device || device->biotype == BIOTYPE_FACE) return ; QString typeString = bioTypeToString(device->biotype); QString moviePath = QString("%1/images/%2.gif").arg(GET_STR(UKUI_BIOMETRIC)).arg(typeString); QMovie *movie = new QMovie(moviePath); movie->setScaledSize(QSize(ui->lblBioImage->width(), ui->lblBioImage->height())); ui->lblBioImage->setMovie(movie); movie->start(); ui->btnRetry->setVisible(false); qDebug() << "set movie " << moviePath; } void BioAuthWidget::setImage() { if(!device || device->biotype == BIOTYPE_FACE) return ; QString typeString = bioTypeToString(device->biotype); QString pixmapPath = QString("%1/images/%2.png").arg(GET_STR(UKUI_BIOMETRIC)).arg(typeString); QPixmap pixmap(pixmapPath); pixmap = pixmap.scaled(ui->lblBioImage->width(), ui->lblBioImage->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); ui->lblBioImage->setPixmap(pixmap); if(BioAuthWidget::failedCount >= nMaxFailCnt) { ui->btnRetry->setVisible(false); } else{ ui->btnRetry->setVisible(true); } qDebug() << "set pixmap " << typeString; } void BioAuthWidget::onFrameWritten(int deviceId) { if(dup_fd == -1){ dup_fd = get_server_gvariant_stdout(deviceId); } cv::Mat img; lseek(dup_fd, 0, SEEK_SET); char base64_bufferData[1024*1024]; int rc = read(dup_fd, base64_bufferData, 1024*1024); printf("rc = %d\n", rc); cv::Mat mat2(1, sizeof(base64_bufferData), CV_8U, base64_bufferData); img = cv::imdecode(mat2, cv::IMREAD_COLOR); cv::cvtColor(img,img,cv::COLOR_BGR2RGB); QImage srcQImage = QImage((uchar*)(img.data), img.cols, img.rows, QImage::Format_RGB888); ui->lblBioImage->setPixmap(QPixmap::fromImage(srcQImage).scaled(ui->lblBioImage->size())); ui->btnRetry->setVisible(false); } void BioAuthWidget::hidePasswdButton() { //ui->btnPasswdAuth->hide(); } bool BioAuthWidget::isAuthenticating() { if(bioAuth){ return bioAuth->isAuthenticating(); } return false; } void BioAuthWidget::stopAuth() { if(bioAuth){ bioAuth->stopAuth(); } } void BioAuthWidget::startAuth(uid_t uid, const DeviceInfoPtr device) { if (!device) { qDebug()<<"Device is invalid!!"; return ; } this->uid = uid; this->device = device; //ui->lblBioDevice->setText(tr("Current Device: ") + device.device_shortname); if(bioAuth) { bioAuth->stopAuth(); delete bioAuth; bioAuth = nullptr; } setMovie(); if(BioAuthWidget::failedCount >= nMaxFailCnt) { // ui->lblBioWarnNotify->setText(tr("Too many unsuccessful attempts,please enter password.")); ui->lblBioWarnNotify->setText(tr("%1 too many unsuccessful attempts,please enter password.").arg(BioDevices::bioTypeToString_tr(device->biotype))); return; } else { ui->lblBioWarnNotify->setText(""); } bioAuth = new BioAuth(uid, device, this); connect(bioAuth, &BioAuth::notify, this, &BioAuthWidget::onBioAuthNotify); connect(bioAuth, &BioAuth::authComplete, this, &BioAuthWidget::onBioAuthComplete); connect(bioAuth, &BioAuth::frameWritten,this,&BioAuthWidget::onFrameWritten); if (device->biotype == REMOTE_QRCODE_TYPE) { onBioAuthNotify(tr("Please use wechat to scan the code")); } dup_fd = -1; fd = -1; bioAuth->startAuth(); } void BioAuthWidget::setMoreDevices(bool hasMore) { //ui->btnMore->setVisible(hasMore); } ukui-biometric-auth/bioauth/src/biodeviceswidget.cpp0000664000175000017500000001071015167732630021646 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "biodeviceswidget.h" #include "ui_biodeviceswidget.h" BioDevicesWidget::BioDevicesWidget(QWidget *parent) : QWidget(parent), ui(new Ui::BioDevicesWidget) { ui->setupUi(this); connect(&bioDevices, &BioDevices::deviceCountChanged, this, &BioDevicesWidget::onDeviceCountChanged); } BioDevicesWidget::~BioDevicesWidget() { delete ui; } void BioDevicesWidget::init(uid_t uid) { this->uid = uid; devicesMap = bioDevices.getUserDevices(uid); ui->cmbDeviceTypes->clear(); for(auto i : devicesMap.keys()) { ui->cmbDeviceTypes->addItem(BioDevices::bioTypeToString_tr(i), i); } /* set the default device as current device */ DeviceInfoPtr device = bioDevices.getDefaultDevice(uid); if(device) { int index = ui->cmbDeviceTypes->findData(device->biotype); QList &deviceList = devicesMap[index]; auto iter = std::find_if(deviceList.constBegin(), deviceList.constEnd(), [&](const DeviceInfo &deviceInfo){ return deviceInfo.device_shortname == device->device_shortname; }); int row = iter - deviceList.constBegin(); //qDebug() << "row==" <lwDevices->currentIndex(); int type = ui->cmbDeviceTypes->itemData(ui->cmbDeviceTypes->currentIndex()).toInt(); qDebug() << "row==" <. * **/ #include "loginoptionswidget.h" #include #include #include #include "giodbus.h" #include "generic.h" #include "biotypes.h" #include #include #include #include #include #include #include #include #include #include #if QT_VERSION_MAJOR == 6 // Qt6中某些头文件路径可能不同 #include #include #else #include #include #endif #include "../common/qt_matrix_compat.h" #include #include #include #include #include LoginOptionsWidget::LoginOptionsWidget(QWidget *parent) : QWidget(parent), m_biomericProxy(new BioAuth(this)), m_bioDevices(new BioDevices()), w_timer(nullptr) { m_bioDevices->recordAuthDrive("polkit", 0, false); initUI(); initConnections(); initStyleTheme(); m_mapDisableDev.clear(); } LoginOptionsWidget::~LoginOptionsWidget() {} void LoginOptionsWidget::initUI() { // 初始化UI m_layoutMain = new QVBoxLayout(); m_layoutMain->setContentsMargins(0, 0, 0, 30); m_layoutMain->setSpacing(12); m_layoutMain->setAlignment(Qt::AlignTop); m_widgetImage = new QWidget(); m_widgetImage->setFixedSize(154, 154); m_layoutImage = new QHBoxLayout(); m_layoutImage->setContentsMargins(0, 8, 0, 16); m_layoutImage->setSpacing(0); m_layoutImage->setAlignment(Qt::AlignCenter); m_layoutImage->addSpacerItem(new QSpacerItem(109, 0, QSizePolicy::Expanding)); m_layoutImage->addWidget(m_widgetImage); m_layoutImage->addSpacerItem(new QSpacerItem(109, 0, QSizePolicy::Expanding)); m_widgetImage->hide(); // 人脸识别 m_labelFace = new QLabel(m_widgetImage); m_labelFace->setObjectName("faceLabel"); m_labelFace->setAlignment(Qt::AlignCenter); m_labelFace->setFixedSize(154, 154); QHBoxLayout *layoutFace = new QHBoxLayout(); layoutFace->setContentsMargins(0, 0, 0, 0); layoutFace->setAlignment(Qt::AlignCenter); m_labelFace->setLayout(layoutFace); m_labelFace->hide(); m_labelFaceLoad = new QLabel(); m_labelFaceLoad->setAlignment(Qt::AlignCenter); m_labelFaceLoad->setFixedSize(142, 142); m_labelFaceLoad->setStyleSheet( QString("QLabel{background-color: rgba(230,230,230,0.39); border-radius: %1px; border: 8px solid white;}") .arg(71)); layoutFace->addWidget(m_labelFaceLoad, 0, Qt::AlignVCenter); // 二维码窗口 m_labelQRCode = new QLabel(m_widgetImage); m_labelQRCode->setObjectName("qrCodeLabel"); m_labelQRCode->setAlignment(Qt::AlignCenter); m_labelQRCode->setFixedSize(154, 154); m_labelQRCode->hide(); QVBoxLayout *layoutQRCode = new QVBoxLayout(); layoutQRCode->setAlignment(Qt::AlignCenter); layoutQRCode->setSpacing(5); m_labelQRCode->setLayout(layoutQRCode); m_labelQRCodeTip = new QLabel(); m_labelQRCodeTip->setFixedSize(22, 22); m_labelQRCodeTip->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(QSize(22, 22))); layoutQRCode->addWidget(m_labelQRCodeTip, 0, Qt::AlignHCenter); m_labelQRCodeMsg = new QLabel(); m_labelQRCodeMsg->setFixedHeight(24); QFont font = m_labelQRCodeMsg->font(); font.setPixelSize(16); m_labelQRCodeMsg->setStyleSheet("QLabel{background-color:rgba(255,255,255,0);color:rgb(255,0,0)}"); m_labelQRCodeMsg->setFont(font); layoutQRCode->addWidget(m_labelQRCodeMsg, 0, Qt::AlignHCenter); // 生物特征等待验证动画 m_labelBioWaiting = new QLabel(m_widgetImage); m_labelBioWaiting->setAlignment(Qt::AlignCenter); m_labelBioWaiting->setFixedSize(154, 154); m_labelBioWaiting->hide(); m_layoutMain->addLayout(m_layoutImage); m_layoutOptBtns = new QHBoxLayout(); m_layoutOptBtns->setContentsMargins(0, 0, 0, 0); m_layoutOptBtns->setSpacing(16); m_labelOptTitle = new QLabel(); m_labelOptTitle->setFixedHeight(30); m_labelOptTitle->setAlignment(Qt::AlignLeft); m_labelOptTitle->setText(tr("Login Options")); m_layoutMain->addWidget(m_labelOptTitle); m_btnGroup = new QButtonGroup(this); m_btnGroup->setExclusive(true); m_layoutOptBtns->setAlignment(Qt::AlignLeft); m_layoutMain->addLayout(m_layoutOptBtns); this->setLayout(m_layoutMain); // 设置水平扩展 QSizePolicy sizePolicy = this->sizePolicy(); sizePolicy.setHorizontalPolicy(QSizePolicy::Expanding); this->setSizePolicy(sizePolicy); } void LoginOptionsWidget::SetExtraInfo(QString extra_info, QString info_type) { if (!m_biomericProxy) { qWarning() << "BiometricProxy doesn't exist."; return; } m_biomericProxy->SetExtraInfo(info_type, extra_info); } void LoginOptionsWidget::initConnections() { if (m_biomericProxy) { connect(m_biomericProxy, &BioAuth::notifyDetail, this, &LoginOptionsWidget::onStatusChanged); connect(m_biomericProxy, &BioAuth::frameWritten, this, &LoginOptionsWidget::onFrameWritten); connect(m_biomericProxy, &BioAuth::authComplete, this, &LoginOptionsWidget::onIdentifyComplete); connect(m_biomericProxy, &BioAuth::authFinished, this, &LoginOptionsWidget::onAuthFinished); } if (m_bioDevices) { connect(m_bioDevices, &BioDevices::deviceCountChanged, this, &LoginOptionsWidget::onUSBDeviceCountChange); // readDevicesInfo(); } connect(m_btnGroup, SIGNAL(buttonClicked(int)), this, SLOT(onOptionSelected(int))); } void LoginOptionsWidget::initStyleTheme() { const QByteArray idd("org.ukui.style"); if (QGSettings::isSchemaInstalled(idd)) { m_styleSettings = new QGSettings(idd); } if (m_styleSettings) { connect(m_styleSettings, &QGSettings::changed, this, [=](const QString &key) { if (key == "styleName") { auto styleNameValue = m_styleSettings->get("styleName"); if (styleNameValue.isValid()) { m_strThemeName = styleNameValue.toString(); } } }); auto styleNameValue = m_styleSettings->get("styleName"); if (styleNameValue.isValid()) { m_strThemeName = styleNameValue.toString(); } } } bool LoginOptionsWidget::getCurLoginOpt(int &nLoginOptType, int &nDrvId) { if (m_curDevInfo) { nLoginOptType = convertDeviceType(m_curDevInfo->biotype); nDrvId = m_curDevInfo->device_id; return true; } return false; } unsigned LoginOptionsWidget::getLoginOptCount() { return m_mapDevices.size(); } DeviceInfoPtr LoginOptionsWidget::getFirstDevInfo() { DeviceInfoPtr devInfo = nullptr; struct passwd *pwdInfo = getpwuid(m_uid); if (!pwdInfo) return devInfo; int nDrvId = m_bioDevices->GetLastDevice(pwdInfo->pw_name); if (nDrvId >= 0) { qDebug() << "GetLastDevice:" << nDrvId; DeviceMap::iterator itDevInfo = m_mapDevices.begin(); for (; itDevInfo != m_mapDevices.end(); itDevInfo++) { for (auto devinfo : itDevInfo.value()) { if (devinfo && devinfo->device_id == nDrvId) { if (!isDeviceDisable(devinfo->device_id)) { devInfo = devinfo; break; } } } if (devInfo) { break; } } } if (!devInfo) { DeviceMap::iterator itDevInfo = m_mapDevices.begin(); for (; itDevInfo != m_mapDevices.end(); itDevInfo++) { for (auto devinfo : itDevInfo.value()) { if (devinfo && !isDeviceDisable(devinfo->device_id)) { devInfo = devinfo; break; } } if (devInfo) { break; } } } return devInfo; } bool LoginOptionsWidget::getHasUkeyOptions() { return isShowUkey; } void LoginOptionsWidget::addOptionButton(unsigned uLoginOptType, int nDrvId, QString strDrvName) { if (m_mapOptBtns.contains(nDrvId)) { return; } QToolButton *newButton = new QToolButton(); newButton->setCheckable(true); newButton->setChecked(false); newButton->setFocusPolicy(Qt::NoFocus); newButton->setContentsMargins(16, 16, 16, 16); int nLength = m_btnGroup->buttons().length(); m_btnGroup->addButton(newButton, nLength); m_listDriveId.append(nDrvId); QIcon icon; switch (uLoginOptType) { case LOGINOPT_TYPE_PASSWORD: icon = QIcon(QString("%1/images/ukui-loginopt-password.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; case LOGINOPT_TYPE_GENERAL_UKEY: icon = QIcon(QString("%1/images/ukui-loginopt-ukey.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; case LOGINOPT_TYPE_FACE: icon = QIcon(QString("%1/images/ukui-loginopt-face.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; case LOGINOPT_TYPE_FINGERPRINT: icon = QIcon(QString("%1/images/ukui-loginopt-finger.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; case LOGINOPT_TYPE_IRIS: icon = QIcon(QString("%1/images/ukui-loginopt-iris.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; case LOGINOPT_TYPE_VOICEPRINT: icon = QIcon(QString("%1/images/ukui-loginopt-voice.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; case LOGINOPT_TYPE_FINGERVEIN: icon = QIcon(QString("%1/images/ukui-loginopt-fingervein.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; case LOGINOPT_TYPE_QRCODE: icon = QIcon(QString("%1/images/ukui-loginopt-qrcode.svg").arg(GET_STR(UKUI_BIOMETRIC))); break; } newButton->setIcon(icon); newButton->setToolTip(strDrvName); newButton->setFixedSize(36, 36); if (isDeviceDisable(nDrvId)) { newButton->setDisabled(true); } else { newButton->setDisabled(false); } m_layoutOptBtns->addWidget(newButton); m_mapOptBtns[nDrvId] = newButton; } void LoginOptionsWidget::clearOptionButtons() { QMap::iterator itMapBtn = m_mapOptBtns.begin(); for (; itMapBtn != m_mapOptBtns.end(); itMapBtn++) { if (itMapBtn.value()) { m_btnGroup->removeButton(itMapBtn.value()); m_layoutOptBtns->removeWidget(itMapBtn.value()); itMapBtn.value()->deleteLater(); } } m_listDriveId.clear(); m_mapOptBtns.clear(); } void LoginOptionsWidget::updateOptionButtons() { isShowUkey = false; clearOptionButtons(); addOptionButton(LOGINOPT_TYPE_PASSWORD, -1, tr("Password")); DeviceMap::iterator itMapDev = m_mapDevices.begin(); for (; itMapDev != m_mapDevices.end(); itMapDev++) { for (DeviceInfoPtr devPtr : itMapDev.value()) { if (devPtr) { if (devPtr->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { // ukey 设备类型排在二维码前,但实际上应该显示在二维码之后,因此暂时不添加 isShowUkey = true; continue; } addOptionButton(itMapDev.key(), devPtr->device_id, BioDevices::bioTypeToString_tr(devPtr->biotype)); } } } itMapDev = m_mapDevices.begin(); if (isShowUkey) { for (; itMapDev != m_mapDevices.end(); itMapDev++) { for (DeviceInfoPtr devPtr : itMapDev.value()) { if (devPtr && devPtr->biotype == LOGINOPT_TYPE_GENERAL_UKEY) { // 此处才添加ukey addOptionButton(itMapDev.key(), devPtr->device_id, BioDevices::bioTypeToString_tr(devPtr->biotype)); } } } } // 存在特征但没有插入ukey if (!isShowUkey && m_biomericProxy->GetHasUkeyFeature(m_uid)) { addOptionButton(LOGINOPT_TYPE_GENERAL_UKEY, -2, BioDevices::bioTypeToString_tr(LOGINOPT_TYPE_GENERAL_UKEY)); isShowUkey = true; } m_labelOptTitle->show(); QMap::iterator itMapBtn = m_mapOptBtns.begin(); for (; itMapBtn != m_mapOptBtns.end(); itMapBtn++) { if (itMapBtn.value()) { itMapBtn.value()->show(); } } } void LoginOptionsWidget::setUser(int uid) { bool bNeedUpdateDevInfo = false; if (uid != m_uid) { bNeedUpdateDevInfo = true; } m_uid = uid; if (bNeedUpdateDevInfo) { if (m_bioDevices) { m_bioDevices->setUId(m_uid); } readDevicesInfo(); } } void LoginOptionsWidget::readDevicesInfo() { m_mapDevices.clear(); bool isAuthEnable = m_bioDevices->GetBioAuthEnable(); bool isQRCodeEnable = m_bioDevices->GetQRCodeEnable(); DeviceList deviceList = m_bioDevices->GetDevList(); QStringList listDefDevices = m_bioDevices->getAllDefDevices(); FeatureMap mapFeatures = m_bioDevices->GetUserFeatures(m_uid); qDebug() << m_uid << ",count:" << mapFeatures.size(); for (auto pDeviceInfo : deviceList) { int nDevFeatureCount = 0; if (m_isInAuth && m_curDevInfo && m_curDevInfo->device_id == pDeviceInfo->device_id) { nDevFeatureCount = 1; } else { if (m_uid == -1) { nDevFeatureCount = 0; } else if (mapFeatures.contains(pDeviceInfo->device_shortname)) { nDevFeatureCount = mapFeatures[pDeviceInfo->device_shortname].size(); } } qDebug() << *pDeviceInfo << ",FeatureCount:" << nDevFeatureCount; if (nDevFeatureCount > 0) { if (!isAuthEnable && pDeviceInfo->biotype <= BIOTYPE_VOICEPRINT) continue; if (!isQRCodeEnable && pDeviceInfo->biotype == REMOTE_QRCODE_TYPE) continue; int nDevType = LOGINOPT_TYPE_OTHERS; nDevType = convertDeviceType(pDeviceInfo->biotype); if ((pDeviceInfo->biotype == REMOTE_QRCODE_TYPE || listDefDevices.contains(pDeviceInfo->device_shortname)) && !m_mapDevices.contains(nDevType)) { m_mapDevices[nDevType].push_back(pDeviceInfo); } } } updateOptionButtons(); updateUIStatus(false); // Q_EMIT notifyOptionsChange(m_mapDevices.size()); } void LoginOptionsWidget::startAuth(DeviceInfoPtr device, int uid) { if (!device || !m_biomericProxy || is_Lock) { qWarning() << "BiometricProxy doesn't exist."; return; } if (m_isInAuth) { qDebug() << "Identification is currently under way, stop it"; stopAuth(); } qDebug() << "deviceInfo:" << device->device_id; this->m_curDevInfo = device; this->m_uid = uid; struct passwd *pwdInfo = getpwuid(uid); if (pwdInfo) { this->m_strUserName = pwdInfo->pw_name; } this->m_isStopped = false; this->m_curLoginOptType = convertDeviceType(this->m_curDevInfo->biotype); updateUIStatus(true); if (pwdInfo) { m_bioDevices->SetLastDevice(pwdInfo->pw_name, this->m_curDevInfo->device_id); } startAuth_(); } void LoginOptionsWidget::setSelectedPassword() { if (m_mapOptBtns.contains(-1)) { QToolButton *btn = m_mapOptBtns[-1]; if (btn && btn->isVisible()) { btn->setChecked(true); } m_curDevInfo = nullptr; } } void LoginOptionsWidget::startAuth_() { if (!m_curDevInfo) return; qDebug().noquote() << QString("Identify:[drvid: %1, uid: %2]").arg(m_curDevInfo->device_id).arg(m_uid); m_isInAuth = true; m_dupFD = -1; if (!w_timer) { w_timer = new QTimer(this); w_timer->setInterval(150); connect(w_timer, &QTimer::timeout, this, &LoginOptionsWidget::updatePixmap); } m_waitingPixmap = QIcon::fromTheme("ukui-loading-0-symbolic").pixmap(24, 24); if (m_curLoginOptType == LOGINOPT_TYPE_QRCODE) { m_labelQRCodeTip->setPixmap(m_waitingPixmap); m_labelQRCodeTip->show(); m_labelQRCodeMsg->hide(); } else if (m_curLoginOptType == LOGINOPT_TYPE_FACE) { m_labelFace->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(230,230,230,0.39);").arg(77)); m_labelFace->setPixmap(QPixmap("")); m_labelFaceLoad->setPixmap(m_waitingPixmap); m_labelFaceLoad->show(); } w_timer->start(); m_bioDevices->recordAuthDrive("polkit", m_curDevInfo->device_id, true); m_biomericProxy->startAuth(m_uid, m_curDevInfo); } void LoginOptionsWidget::stopAuth() { m_isStopped = true; if (!m_isInAuth || !m_curDevInfo) { return; } m_biomericProxy->stopAuth(); if (m_retrytimer && m_retrytimer->isActive()) { m_retrytimer->stop(); delete m_retrytimer; m_retrytimer = nullptr; } m_isInAuth = false; Q_EMIT updateImage(QImage()); QImage img; setFaceImg(img); } void LoginOptionsWidget::updatePixmap() { QMatrix matrix; matrix.rotate(90.0); m_waitingPixmap = QtPixmapCompat::transformedPixmap(m_waitingPixmap, matrix, Qt::FastTransformation); if (m_curLoginOptType == LOGINOPT_TYPE_QRCODE) m_labelQRCodeTip->setPixmap(m_waitingPixmap); else if (m_curLoginOptType == LOGINOPT_TYPE_FACE) { m_labelFaceLoad->setPixmap(m_waitingPixmap); } } void LoginOptionsWidget::onAuthFinished() { if (m_bioDevices) { m_bioDevices->recordAuthDrive("polkit", 0, false); } } void LoginOptionsWidget::onIdentifyComplete(int uid, bool ret, int retErrNo) { if (m_isStopped == true) return; if (uid < 0) { readDevicesInfo(); Q_EMIT authComplete(uid, false, -1); return; } qDebug() << retErrNo << uid << m_uid; // 特征识别成功,而且用户id匹配 if (retErrNo == DBUS_RESULT_SUCCESS && uid == m_uid) { qDebug() << "Identify success"; Q_EMIT authComplete(uid, true, 0); } else if (retErrNo == -1) { // 特征识别不匹配 qDebug() << "Identify failed"; Q_EMIT authComplete(uid, false, 2); } else if (retErrNo == -2) { // 识别发生错误 StatusReslut ret = m_bioDevices->UpdateStatus(m_curDevInfo->device_id); qDebug() << "StatusReslut:" << ret.result << "," << ret.enable << "," << ret.devNum << "," << ret.devStatus << "," << ret.opsStatus << "," << ret.notifyMessageId; // 识别操作超时 if (ret.result == 0 && ret.opsStatus == 10) { // 10 当前时间错误导致网络错误 Q_EMIT authComplete(uid, false, -4); } else if ( ret.result == 0 && (ret.opsStatus == 404 || ret.opsStatus == 304 || ret.opsStatus == 8)) { // 304认证超时, 8网络异常 Q_EMIT authComplete(uid, false, 1); } else if (ret.opsStatus == OPS_IDENTIFY_STOP_BY_USER || ret.opsStatus == OPS_VERIFY_STOP_BY_USER) { Q_EMIT authComplete(uid, false, -2); // 主动停止,直接重试 } else if ( ret.opsStatus == OPS_OPEN_FAIL || ret.opsStatus == OPS_OPEN_ERROR) { // 无法打开设备(设备是坏的/被占用),直接禁用 Q_EMIT authComplete(uid, false, 5); } else { Q_EMIT authComplete(uid, false, 2); } } else { Q_EMIT authComplete(uid, false, 2); } } QPixmap LoginOptionsWidget::PixmapToRound(const QPixmap &src, int radius) { if (src.isNull()) { return QPixmap(); } QPixmap pixmapa(src); QPixmap pixmap(radius * 2, radius * 2); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); QPainterPath path; path.addEllipse(0, 0, radius * 2, radius * 2); painter.setClipPath(path); painter.drawPixmap(0, 0, radius * 2, radius * 2, pixmapa); return pixmap; } /** * @brief scaledPixmap * @param width * @param height * @param url * @return * 图片缩放 */ QPixmap LoginOptionsWidget::scaledPixmap(int width, int height, QString url) { QFile imgFile(url); if (!imgFile.exists()) { qDebug() << "not find the pixmap file"; return QPixmap(); } QImage image(url); QPixmap pixmap = QPixmap::fromImage(image); if (pixmap.isNull()) { qDebug() << "pixmap is null"; QProcess exec; QString program("file " + url); exec.start(program); exec.waitForFinished(1000); QString output = exec.readAllStandardOutput(); qDebug() << output; if (output.contains("SVG")) { qDebug() << "image format is SVG"; QSvgRenderer render(url); QImage image(width, height, QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter painter(&image); render.render(&painter, image.rect()); pixmap.convertFromImage(image); } else if (output.contains("TIFF")) { qDebug() << "image format is TIFF"; } } return pixmap.scaled(width, height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); } void LoginOptionsWidget::onFrameWritten(int drvid) { if (!m_curDevInfo) return; if (m_curDevInfo && m_curDevInfo->device_id != drvid || !m_isInAuth) { return; } if (m_dupFD == -1) { m_dupFD = get_server_gvariant_stdout(drvid); } if (m_dupFD <= 0) return; cv::Mat img; lseek(m_dupFD, 0, SEEK_SET); char base64_bufferData[1024 * 1024]; int rc = read(m_dupFD, base64_bufferData, 1024 * 1024); Q_UNUSED(rc); // printf("rc = %d\n", rc); cv::Mat mat2(1, sizeof(base64_bufferData), CV_8U, base64_bufferData); img = cv::imdecode(mat2, cv::IMREAD_COLOR); if (!img.data) return; cv::cvtColor(img, img, cv::COLOR_BGR2RGB); QImage srcQImage = QImage((uchar *)(img.data), img.cols, img.rows, QImage::Format_RGB888); if (isAuthenticating()) { if (m_curLoginOptType == LOGINOPT_TYPE_FACE) { m_labelFace->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(255,255,255,10%);") .arg(77)); setFaceImg(srcQImage); m_labelFace->show(); m_labelQRCode->hide(); } else if (m_curLoginOptType == LOGINOPT_TYPE_QRCODE) { m_labelQRCode->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(255,255,255,100%);") .arg(6)); setQRCode(srcQImage); m_labelQRCode->show(); m_labelQRCodeTip->hide(); m_labelFace->hide(); } else { m_labelFace->hide(); m_labelQRCode->hide(); } } else { m_labelFace->hide(); m_labelQRCode->hide(); } if (w_timer && w_timer->isActive()) { w_timer->stop(); } Q_EMIT updateImage(srcQImage); } void LoginOptionsWidget::setQRCode(QImage &imgQRCode) { if (imgQRCode.isNull()) { imgQRCode.load(QString("%1/images/ukui-qrcode-null.svg").arg(GET_STR(UKUI_BIOMETRIC))); } imgQRCode = imgQRCode.scaled(QSize(150, 150)); m_labelQRCode->setAlignment(Qt::AlignCenter); m_labelQRCode->setPixmap(QPixmap::fromImage(imgQRCode)); } void LoginOptionsWidget::setQRCodeMsg(QString strMsg) { if (strMsg.isEmpty()) { m_labelQRCodeMsg->hide(); // m_labelQRCodeTip->hide(); } else { // 一开始认证时就没有网,直接停止加载状态 if (w_timer && w_timer->isActive()) { w_timer->stop(); } m_labelQRCodeMsg->setText(strMsg); m_labelQRCodeMsg->show(); m_labelQRCodeTip->show(); m_labelQRCodeTip->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(QSize(22, 22))); } } void LoginOptionsWidget::setFaceImg(QImage &imgFace, int nStatus) { QPixmap faceImage; m_labelFace->setFixedSize(154, 154); // 如果头像文件不存在,则使用默认头像 if (!imgFace.isNull()) { faceImage = PixmapToRound(QPixmap::fromImage(imgFace), 77); } else { switch (nStatus) { case 1: faceImage = loadSvg(QString("%1/images/ukui-loginopt-lose.svg").arg(GET_STR(UKUI_BIOMETRIC)), "black", 48); m_labelFace->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(230,230,230,40%);") .arg(77)); break; case 2: faceImage = loadSvg(QString("%1/images/ukui-loginopt-smile.svg").arg(GET_STR(UKUI_BIOMETRIC)), "gray", 48); m_labelFace->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(230,230,230,100%);") .arg(77)); break; default: faceImage = loadSvg(QString("%1/images/ukui-loginopt-smile.svg").arg(GET_STR(UKUI_BIOMETRIC)), "black", 48); m_labelFace->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(230,230,230,40%);") .arg(77)); break; } } m_labelFace->setAlignment(Qt::AlignCenter); m_labelFace->setPixmap(faceImage); m_labelFaceLoad->hide(); } void LoginOptionsWidget::onStatusChanged(int drvid, const QString &message) { if (!m_isInAuth || !m_curDevInfo) { return; } if (drvid != m_curDevInfo->device_id) { return; } // Q_EMIT updateAuthMsg(message); } void LoginOptionsWidget::setCurrentDevice(int drvid) { DeviceInfoPtr pDeviceInfo = findDeviceById(drvid); if (pDeviceInfo) { setCurrentDevice(pDeviceInfo); } } void LoginOptionsWidget::setCurrentDevice(const QString &deviceName) { DeviceInfoPtr pDeviceInfo = findDeviceByName(deviceName); if (pDeviceInfo) { setCurrentDevice(pDeviceInfo); } } void LoginOptionsWidget::setCurrentDevice(const DeviceInfoPtr &pDeviceInfo) { this->m_curDevInfo = pDeviceInfo; } DeviceInfoPtr LoginOptionsWidget::findDeviceById(int drvid) { for (int type : m_mapDevices.keys()) { DeviceList &deviceList = m_mapDevices[type]; auto iter = std::find_if( deviceList.begin(), deviceList.end(), [&](DeviceInfoPtr ptr) { return ptr->device_id == drvid; }); if (iter != deviceList.end()) { return *iter; } } return DeviceInfoPtr(); } DeviceInfoPtr LoginOptionsWidget::findDeviceByName(const QString &name) { for (int type : m_mapDevices.keys()) { DeviceList &deviceList = m_mapDevices[type]; auto iter = std::find_if( deviceList.begin(), deviceList.end(), [&](DeviceInfoPtr ptr) { return ptr->device_shortname == name; }); if (iter != deviceList.end()) { return *iter; } } return DeviceInfoPtr(); } QString LoginOptionsWidget::GetDefaultDevice(uid_t uid, int bioType) { QString defaultDeviceName = ""; DeviceInfoPtr pDeviceInfo = m_bioDevices->getDefaultDevice(uid, bioType); if (pDeviceInfo) { defaultDeviceName = pDeviceInfo->device_shortname; } qDebug() << "default device: " << defaultDeviceName; return defaultDeviceName; } QString LoginOptionsWidget::GetDefaultDevice(uid_t uid) { QString defaultDeviceName = ""; DeviceInfoPtr pDeviceInfo = m_bioDevices->getDefaultDevice(uid); if (pDeviceInfo) { defaultDeviceName = pDeviceInfo->device_shortname; } qDebug() << "default device: " << defaultDeviceName; return defaultDeviceName; } void LoginOptionsWidget::onUSBDeviceCountChange(int newNum) { qDebug() << "deviceNewNum:" << newNum; int savedCount = 0; for (int type : m_mapDevices.keys()) savedCount += m_mapDevices.value(type).count(); readDevicesInfo(); int count = 0; for (int type : m_mapDevices.keys()) count += m_mapDevices.value(type).count(); // 设备数量发生了变化 if (count != savedCount) { updateOptionButtons(); Q_EMIT notifyOptionsChange(count); } updateUIStatus(false); } void LoginOptionsWidget::updateUkeyUIStatus(int type) { m_labelFace->hide(); m_labelQRCode->hide(); m_widgetImage->hide(); setFixedHeight(m_labelOptTitle->height() + 12 + 36); Q_EMIT this->updateWndSize(this->m_curLoginOptType, this->m_mapOptBtns.size()); } void LoginOptionsWidget::updateUIStatus(bool update, int nPreOptType /* = -1*/) { if (m_mapOptBtns.contains(-1)) { QToolButton *btn = m_mapOptBtns[-1]; if (btn && btn->isVisible()) { btn->setChecked(true); } } if (m_curDevInfo) { if (m_mapOptBtns.contains(m_curDevInfo->device_id)) { QToolButton *btn = m_mapOptBtns[m_curDevInfo->device_id]; if (btn) { btn->setChecked(true); } } } if (update) { bool isSameType = false; if (nPreOptType != -1) { isSameType = (m_curLoginOptType == nPreOptType); m_curLoginOptType = nPreOptType; } if (m_curLoginOptType == LOGINOPT_TYPE_FACE) { m_labelFace->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(255,255,255,10%);") .arg(77)); m_labelFace->show(); m_labelQRCode->hide(); m_widgetImage->show(); setFixedHeight(m_labelOptTitle->height() + 12 + 36 + 12 + 154 + 48); } else if (m_curLoginOptType == LOGINOPT_TYPE_QRCODE) { if (!isSameType) { m_labelQRCode->setStyleSheet( QString("border-radius: %1px; border:0px solid white;background-color: rgba(255,255,255,100%);") .arg(6)); QImage img; setQRCode(img); m_labelQRCode->show(); m_labelFace->hide(); m_widgetImage->show(); setFixedHeight(m_labelOptTitle->height() + 12 + 36 + 12 + 154 + 48); } } else { m_labelFace->hide(); m_labelQRCode->hide(); if (m_curLoginOptType == LOGINOPT_TYPE_FINGERPRINT || m_curLoginOptType == LOGINOPT_TYPE_FINGERVEIN || m_curLoginOptType == LOGINOPT_TYPE_IRIS || m_curLoginOptType == LOGINOPT_TYPE_VOICEPRINT) { m_widgetImage->show(); setFixedHeight(m_labelOptTitle->height() + 12 + 36 + 12 + 154 + 48); } else { m_widgetImage->hide(); setFixedHeight(m_labelOptTitle->height() + 12 + 36 + 24); } } Q_EMIT this->updateWndSize(this->m_curLoginOptType, this->m_mapOptBtns.size()); } } void LoginOptionsWidget::onOptionSelected(int nIndex) { if (nIndex < 0) return; if (nIndex < m_listDriveId.size()) { DeviceInfoPtr info = findDeviceById(m_listDriveId[nIndex]); if (info && !isDeviceDisable(info->device_id)) { Q_EMIT optionSelected(convertDeviceType(info->biotype), info); this->m_curLoginOptType = convertDeviceType(info->biotype); } else if (nIndex == 0 && m_listDriveId[nIndex] == -1) { stopAuth(); m_curDevInfo = nullptr; Q_EMIT optionSelected(LOGINOPT_TYPE_PASSWORD, nullptr); this->m_curLoginOptType = LOGINOPT_TYPE_PASSWORD; } else if (m_listDriveId[nIndex] == -2) { // 存在ukey特征,但未插入ukey stopAuth(); m_curDevInfo = nullptr; Q_EMIT optionSelected(LOGINOPT_TYPE_GENERAL_UKEY, nullptr); this->m_curLoginOptType = LOGINOPT_TYPE_GENERAL_UKEY; } } } int LoginOptionsWidget::convertDeviceType(int nDevType) { int nLoginOptType = LOGINOPT_TYPE_OTHERS; switch (nDevType) { case BIOTYPE_FINGERPRINT: nLoginOptType = LOGINOPT_TYPE_FINGERPRINT; break; case BIOTYPE_FINGERVEIN: nLoginOptType = LOGINOPT_TYPE_FINGERVEIN; break; case BIOTYPE_IRIS: nLoginOptType = LOGINOPT_TYPE_IRIS; break; case BIOTYPE_FACE: nLoginOptType = LOGINOPT_TYPE_FACE; break; case BIOTYPE_VOICEPRINT: nLoginOptType = LOGINOPT_TYPE_VOICEPRINT; break; case UniT_General_Ukey: nLoginOptType = LOGINOPT_TYPE_GENERAL_UKEY; break; case UniT_Advanced_Ukey: nLoginOptType = LOGINOPT_TYPE_ADVANCED_UKEY; break; case REMOTE_QRCODE_TYPE: nLoginOptType = LOGINOPT_TYPE_QRCODE; break; default: nLoginOptType = LOGINOPT_TYPE_OTHERS; break; } return nLoginOptType; } void LoginOptionsWidget::setDeviceDisable(int nDevId, bool bDisable) { if (bDisable) { m_mapDisableDev[m_uid][nDevId] = true; QMap::iterator itMapBtn = m_mapOptBtns.begin(); for (; itMapBtn != m_mapOptBtns.end(); itMapBtn++) { if (itMapBtn.key() == nDevId && itMapBtn.value()) { itMapBtn.value()->setDisabled(true); break; } } } else { m_mapDisableDev[m_uid][nDevId] = false; QMap::iterator itMapBtn = m_mapOptBtns.begin(); for (; itMapBtn != m_mapOptBtns.end(); itMapBtn++) { if (itMapBtn.key() == nDevId && itMapBtn.value()) { itMapBtn.value()->setDisabled(false); break; } } } } void LoginOptionsWidget::setAllDeviceDisable(bool bDisable) { if (bDisable) { QMap::iterator itMapBtn = m_mapOptBtns.begin(); for (; itMapBtn != m_mapOptBtns.end(); itMapBtn++) { m_mapDisableDev[m_uid][itMapBtn.key()] = true; if (itMapBtn.value()) { itMapBtn.value()->setDisabled(true); } } } else { QMap::iterator itMapBtn = m_mapOptBtns.begin(); for (; itMapBtn != m_mapOptBtns.end(); itMapBtn++) { m_mapDisableDev[m_uid][itMapBtn.key()] = false; if (itMapBtn.value()) { itMapBtn.value()->setDisabled(false); } } } } bool LoginOptionsWidget::isDeviceDisable(int nDevId) { if (m_mapDisableDev[m_uid].contains(nDevId)) { return m_mapDisableDev[m_uid][nDevId]; } return false; } void LoginOptionsWidget::lockStatusChanged(bool locked) { if (locked) { is_Lock = true; stopAuth(); } else { is_Lock = false; readDevicesInfo(); } } QPixmap LoginOptionsWidget::loadSvg(QString path, QString color, int size) { int origSize = size; const auto ratio = qApp->devicePixelRatio(); if (2 == ratio) { size += origSize; } else if (3 == ratio) { size += origSize; } QPixmap pixmap(size, size); QSvgRenderer renderer(path); pixmap.fill(Qt::transparent); QPainter painter; painter.begin(&pixmap); renderer.render(&painter); painter.end(); pixmap.setDevicePixelRatio(ratio); return drawSymbolicColoredPixmap(pixmap, color); } QPixmap LoginOptionsWidget::drawSymbolicColoredPixmap(QPixmap &source, QString cgColor) { QImage img = source.toImage(); for (int x = 0; x < img.width(); x++) { for (int y = 0; y < img.height(); y++) { auto color = img.pixelColor(x, y); if (color.alpha() > 0) { if ("white" == cgColor) { color.setRed(255); color.setGreen(255); color.setBlue(255); img.setPixelColor(x, y, color); } else if ("black" == cgColor) { color.setRed(0); color.setGreen(0); color.setBlue(0); img.setPixelColor(x, y, color); } else if ("gray" == cgColor) { color.setRed(152); color.setGreen(163); color.setBlue(164); img.setPixelColor(x, y, color); } else if ("blue" == cgColor) { color.setRed(61); color.setGreen(107); color.setBlue(229); img.setPixelColor(x, y, color); } else { return source; } } } } return QPixmap::fromImage(img); } QPixmap LoginOptionsWidget::scaledSmoothPixmap(const QPixmap &src, int nWidth, int nHeight) { if (src.isNull()) { return QPixmap(); } QPixmap pixmapa(src); QPixmap pixmap(nWidth, nHeight); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter.drawPixmap(0, 0, nWidth, nHeight, pixmapa); return pixmap; } void LoginOptionsWidget::startBioWaiting(unsigned uCurLoginOptType) { if (uCurLoginOptType == m_nCurBioWaitingType || (uCurLoginOptType != LOGINOPT_TYPE_FINGERPRINT && uCurLoginOptType != LOGINOPT_TYPE_FINGERVEIN && uCurLoginOptType != LOGINOPT_TYPE_IRIS && uCurLoginOptType != LOGINOPT_TYPE_VOICEPRINT)) { return; } m_nCurBioWaitingType = uCurLoginOptType; if (!m_timerBioWaiting) { m_timerBioWaiting = new QTimer(this); m_timerBioWaiting->setInterval(100); } if (m_timerBioWaiting) { if (m_timerBioWaiting->isActive()) { m_timerBioWaiting->stop(); } // 重新连接信号槽 disconnect(m_timerBioWaiting, nullptr, this, nullptr); connect(m_timerBioWaiting, &QTimer::timeout, this, [&, this, uCurLoginOptType]() { m_nBioWaitingFrame += 1; QString strPicName = ""; QString strBasePath = ":/image/assets/biowaiting"; if (m_strThemeName == "ukui-dark" || m_strThemeName == "ukui-black") { strBasePath = ":/image/assets/biowaiting/dark"; } switch (uCurLoginOptType) { case LOGINOPT_TYPE_FINGERPRINT: { if (m_nBioWaitingFrame >= 15) { m_nBioWaitingFrame = 0; } strPicName = QString("%1/fingerprint%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_FINGERVEIN: { if (m_nBioWaitingFrame >= 12) { m_nBioWaitingFrame = 0; } strPicName = QString("%1/fingervein%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_IRIS: { if (m_nBioWaitingFrame >= 12) { m_nBioWaitingFrame = 0; } strPicName = QString("%1/iris%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_VOICEPRINT: { if (m_nBioWaitingFrame >= 8) { m_nBioWaitingFrame = 0; } strPicName = QString("%1/voiceprint%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; default: break; } if (!strPicName.isEmpty()) { QPixmap pixmap; if (QPixmapCache::find(strPicName, &pixmap)) { m_labelBioWaiting->setPixmap(pixmap); } else { pixmap = scaledSmoothPixmap(QPixmap(strPicName), 154, 154); if (!pixmap.isNull()) { QPixmapCache::insert(strPicName, pixmap); m_labelBioWaiting->setPixmap(pixmap); } } m_labelBioWaiting->show(); } }); m_timerBioWaiting->start(); m_nBioWaitingFrame = 0; QString strPicName = ""; QString strBasePath = ":/image/assets/biowaiting"; if (m_strThemeName == "ukui-dark" || m_strThemeName == "ukui-black") { strBasePath = ":/image/assets/biowaiting/dark"; } switch (uCurLoginOptType) { case LOGINOPT_TYPE_FINGERPRINT: { strPicName = QString("%1/fingerprint%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_FINGERVEIN: { strPicName = QString("%1/fingervein%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_IRIS: { strPicName = QString("%1/iris%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_VOICEPRINT: { strPicName = QString("%1/voiceprint%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; default: break; } if (!strPicName.isEmpty()) { QPixmap pixmap; if (QPixmapCache::find(strPicName, &pixmap)) { m_labelBioWaiting->setPixmap(pixmap); } else { pixmap = scaledSmoothPixmap(QPixmap(strPicName), 154, 154); if (!pixmap.isNull()) { QPixmapCache::insert(strPicName, pixmap); m_labelBioWaiting->setPixmap(pixmap); } } m_labelBioWaiting->show(); } } } void LoginOptionsWidget::stopBioWaiting(bool isDisable /* = false*/) { if (m_timerBioWaiting) { if (m_timerBioWaiting->isActive()) { m_timerBioWaiting->stop(); } } m_nBioWaitingFrame = 0; if (isDisable) { QString strPicName = ""; QString strBasePath = ":/image/assets/biowaiting"; if (m_strThemeName == "ukui-dark" || m_strThemeName == "ukui-black") { strBasePath = ":/image/assets/biowaiting/dark"; } switch (m_nCurBioWaitingType) { case LOGINOPT_TYPE_FINGERPRINT: { strPicName = QString("%1/fingerprint%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_FINGERVEIN: { strPicName = QString("%1/fingervein%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_IRIS: { strPicName = QString("%1/iris%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; case LOGINOPT_TYPE_VOICEPRINT: { strPicName = QString("%1/voiceprint%2.svg").arg(strBasePath).arg(m_nBioWaitingFrame); } break; default: break; } if (!strPicName.isEmpty()) { QPixmap pixmap; if (QPixmapCache::find(strPicName, &pixmap)) { m_labelBioWaiting->setPixmap(pixmap); } else { pixmap = scaledSmoothPixmap(QPixmap(strPicName), 154, 154); if (!pixmap.isNull()) { QPixmapCache::insert(strPicName, pixmap); m_labelBioWaiting->setPixmap(pixmap); } } } } else { m_labelBioWaiting->hide(); } m_nCurBioWaitingType = -1; } ukui-biometric-auth/bioauth/src/bioauth.cpp0000664000175000017500000001651615167732644020000 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "bioauth.h" #include #include #include BioAuth::BioAuth(qint32 uid, const DeviceInfoPtr deviceInfo, QObject *parent) : QObject(parent), uid(uid), deviceInfo(deviceInfo), isInAuthentication(false) { init(); } BioAuth::BioAuth(QObject *parent) : QObject(parent) , isInAuthentication(false) { init(); } void BioAuth::init() { serviceInterface = new QDBusInterface(BIO_DBUS_SERVICE, BIO_DBUS_PATH, BIO_DBUS_INTERFACE, QDBusConnection::systemBus()); connect(serviceInterface, SIGNAL(StatusChanged(int, int)), this, SLOT(onStatusChanged(int,int))); connect(serviceInterface, SIGNAL(FrameWritten(int)), this, SLOT(onFrameWritten(int))); serviceInterface->setTimeout(2147483647); } BioAuth::~BioAuth() { // stopAuth(); } void BioAuth::setDevice(const DeviceInfoPtr deviceInfo) { this->deviceInfo = deviceInfo; } void BioAuth::setUid(qint32 uid) { this->uid = uid; } void BioAuth::startUkeyAuth() { // stopAuth(); if (!deviceInfo) { qDebug()<<"DeviceInfo not valid!!"; return; } /* 开始认证识别 */ LOG() << "start biometric verification"; QList args; args << QVariant(deviceInfo->device_id) << QVariant(2) << QVariant(uid); isInAuthentication = true; QDBusPendingCall call = serviceInterface->asyncCallWithArgumentList("UkeyIdentify", args); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &BioAuth::onIdentityComplete); } DeviceInfoPtr BioAuth::getDevice() { return this->deviceInfo; } void BioAuth::startAuth() { // stopAuth(); if (!deviceInfo) { qDebug()<<"DeviceInfo not valid!!"; return; } /* 开始认证识别 */ LOG() << "start biometric verification"; QList args; args << QVariant(deviceInfo->device_id) << QVariant(uid) << QVariant(0) << QVariant(-1); isInAuthentication = true; qDebug()<biotype == LOGINOPT_TYPE_GENERAL_UKEY){ QList args1; args1 << QVariant(deviceInfo->device_id) << QVariant(2) << QVariant(uid); QDBusPendingCall call = serviceInterface->asyncCallWithArgumentList("UkeyIdentify", args1); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &BioAuth::onIdentityComplete); }else{ //使用sudo等命令时,不停止设备,当存在其他可认证设备时,使用其他可认证设备,否则使用密码 if(qAppName() != "bioauth"){ //stopops在identify之前使用时,不要调用getFeaturelist,否则会出现identify被停止的现象,应该时框架的bug。 serviceInterface->call("StopOps", QVariant(deviceInfo->device_id), QVariant(3000)); } QDBusPendingCall call = serviceInterface->asyncCallWithArgumentList("Identify", args); QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &BioAuth::onIdentityComplete); } } bool BioAuth::GetHasUkeyFeature(int uid, int indexStart, int indexEnd) { QList qlist; FeatureInfo *featureInfo; int listsize; QDBusMessage result = serviceInterface->call(QStringLiteral("GetAllFeatureList"),uid,indexStart,indexEnd); if(result.type() == QDBusMessage::ErrorMessage) { qWarning() << "GetDevList error:" << result.errorMessage(); return false; } QList variantList = result.arguments(); listsize = variantList[0].value(); variantList[1].value() >> qlist; for (int i = 0; i < listsize; i++) { featureInfo = new FeatureInfo; qlist[i].variant().value() >> *featureInfo; if(featureInfo->biotype == LOGINOPT_TYPE_GENERAL_UKEY){ delete featureInfo; return true; } delete featureInfo; } return false; } int BioAuth::SetExtraInfo(QString info_type,QString extra_info) { QDBusReply reply = serviceInterface->call(QStringLiteral("SetExtraInfo"), info_type, extra_info); if(!reply.isValid()) { qWarning() << "SetExtraInfo error:" << reply.error(); return -1; } return reply.value(); } void BioAuth::startAuth(qint32 uid, const DeviceInfoPtr deviceInfo) { if (!deviceInfo) { return ; } this->uid = uid; this->deviceInfo = deviceInfo; startAuth(); } void BioAuth::stopAuth() { if(!isInAuthentication) return ; if (!deviceInfo) { qDebug()<<"DeviceInfo not valid!!"; return; } QDBusReply reply = serviceInterface->call("StopOps", QVariant(deviceInfo->device_id), QVariant(3000)); emit authFinished(); if(!reply.isValid()) qWarning() << "StopOps error: " << reply.error(); isInAuthentication = false; } bool BioAuth::isAuthenticating() { return isInAuthentication; } void BioAuth::onIdentityComplete(QDBusPendingCallWatcher *watcher) { emit authFinished(); QDBusPendingReply reply = *watcher; if(reply.isError()){ isInAuthentication = false; LOG() << reply.error(); Q_EMIT authComplete(-1, false, -1); return; } qint32 result = reply.argumentAt(0).toInt(); qint32 retUid = reply.argumentAt(1).toInt(); LOG() << "Identify complete: " << result << " " << retUid << " " << uid; /* 识别生物特征成功,发送认证结果 */ if(isInAuthentication){ isInAuthentication = false; if(result == DBUS_RESULT_SUCCESS && retUid == uid){ Q_EMIT authComplete(retUid, true, result); }else { Q_EMIT authComplete(uid, false, result); } } } void BioAuth::onFrameWritten(int deviceId) { Q_EMIT frameWritten(deviceId); } void BioAuth::onStatusChanged(int deviceId, int statusType) { if(statusType != STATUS_NOTIFY) return; LOG() << "status changed " << deviceId << " " << statusType; QDBusMessage msg = serviceInterface->call("GetNotifyMesg", QVariant(deviceId)); if(msg.type() == QDBusMessage::ErrorMessage){ LOG() << msg.errorMessage(); return; } if(deviceInfo && deviceInfo->device_id != deviceId){ return ; } QString message = msg.arguments().at(0).toString(); LOG() << message; Q_EMIT notify(message); Q_EMIT notifyDetail(deviceId, message); } ukui-biometric-auth/bioauth/src/biotypes.cpp0000664000175000017500000000726215167732630020174 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "biotypes.h" #include QDBusArgument &operator<<(QDBusArgument &argument, const DeviceInfo &deviceInfo) { argument.beginStructure(); argument << deviceInfo.device_id << deviceInfo.device_shortname << deviceInfo.device_fullname << deviceInfo.driver_enable << deviceInfo.device_available << deviceInfo.biotype << deviceInfo.stotype << deviceInfo.eigtype << deviceInfo.vertype << deviceInfo.idtype << deviceInfo.bustype << deviceInfo.dev_status << deviceInfo.ops_status; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, DeviceInfo &deviceInfo) { argument.beginStructure(); argument >> deviceInfo.device_id >> deviceInfo.device_shortname >> deviceInfo.device_fullname >> deviceInfo.driver_enable >> deviceInfo.device_available >> deviceInfo.biotype >> deviceInfo.stotype >> deviceInfo.eigtype >> deviceInfo.vertype >> deviceInfo.idtype >> deviceInfo.bustype >> deviceInfo.dev_status >> deviceInfo.ops_status; argument.endStructure(); return argument; } bool DeviceInfo::operator==(const DeviceInfo& deviceInfo) const { if(this->device_shortname == deviceInfo.device_shortname && this->device_available == deviceInfo.device_available) return true; return false; } QDebug& operator<<(QDebug &stream, const DeviceInfo &deviceInfo) { stream << deviceInfo.device_id << deviceInfo.device_shortname << deviceInfo.biotype << deviceInfo.device_available; return stream; } QDebug operator <<(QDebug stream, const DeviceInfo &deviceInfo) { stream << "[" << deviceInfo.device_id << deviceInfo.device_shortname << deviceInfo.device_fullname << deviceInfo.biotype << deviceInfo.driver_enable << deviceInfo.device_available << "]"; return stream; } /* For the type FeatureInfo */ QDBusArgument &operator<<(QDBusArgument &argument, const FeatureInfo &featureInfo) { argument.beginStructure(); argument << featureInfo.uid << featureInfo.biotype << featureInfo.device_shortname << featureInfo.index << featureInfo.index_name; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, FeatureInfo &featureInfo) { argument.beginStructure(); argument >> featureInfo.uid >> featureInfo.biotype >> featureInfo.device_shortname >> featureInfo.index >> featureInfo.index_name; argument.endStructure(); return argument; } QString bioTypeToString(int type) { switch(type) { case BIOTYPE_FINGERPRINT: return ("FingerPrint"); case BIOTYPE_FINGERVEIN: return ("FingerVein"); case BIOTYPE_IRIS: return ("Iris"); case BIOTYPE_FACE: return ("Face"); case LOGINOPT_TYPE_GENERAL_UKEY: return ("ukey"); case BIOTYPE_VOICEPRINT: return ("VoicePrint"); } return QString(); } ukui-biometric-auth/bioauth/src/biodevices.cpp0000664000175000017500000006263715167732644020466 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "biodevices.h" #include #include #include #include #include #include #include #include "generic.h" BioDevices::BioDevices(bool isIgnoreQrCode, QObject *parent) : QObject(parent) , m_uniAuthService(new UniAuthService(this)) , isShowHotPlug(false) , useFirstDevice(false) , m_isIgnoreQrCode(isIgnoreQrCode) { connectToService(); m_listPriority.clear(); m_listPriority.push_back(BIOTYPE_FACE); m_listPriority.push_back(BIOTYPE_FINGERPRINT); m_listPriority.push_back(BIOTYPE_IRIS); m_listPriority.push_back(BIOTYPE_VOICEPRINT); m_listPriority.push_back(BIOTYPE_FINGERVEIN); m_listPriority.push_back(REMOTE_QRCODE_TYPE); m_listPriority.push_back(LOGINOPT_TYPE_GENERAL_UKEY); } void BioDevices::setUId(int nUId) { m_nUId = nUId; getDevicesList(); } void BioDevices::connectToService() { qRegisterMetaType(); qDBusRegisterMetaType(); serviceInterface = new QDBusInterface(BIO_DBUS_SERVICE, BIO_DBUS_PATH, BIO_DBUS_INTERFACE, QDBusConnection::systemBus()); connect(serviceInterface, SIGNAL(USBDeviceHotPlug(int, int, int)), this, SLOT(onUSBDeviceHotPlug(int, int, int))); serviceInterface->setTimeout(2147483647); } void BioDevices::onUSBDeviceHotPlug(int deviceId, int action, int devNumNow) { qDebug() << deviceId << action << devNumNow; QString text = ""; if (action == -1) { DeviceInfoPtr device = findDevice(deviceId); if (device) text = tr("Unplugging of %1 device detected").arg(bioTypeToString_tr(device->biotype)); } getDevicesList(); emit deviceCountChanged(deviceInfos.size()); if (action == 1) { DeviceInfoPtr device = findDevice(deviceId); if (device) text = tr("%1 device insertion detected").arg(bioTypeToString_tr(device->biotype)); } if (isShowHotPlug && text != "") { QDBusInterface iface( "org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()); QList args; args << (tr("Biometric Manager")) << ((unsigned int)0) << "biometric-manager" << tr("biometric") << text << QStringList() << QVariantMap() << (int)-1; iface.callWithArgumentList(QDBus::AutoDetect, "Notify", args); } } bool BioDevices::GetBioAuthEnable(uid_t uid) { if (m_uniAuthService && m_uniAuthService->isActivatable()) { struct passwd *pwd = getpwuid(uid); if (pwd) { return m_uniAuthService->getBioAuthStatus(pwd->pw_name, ENABLETYPE_BIO); } else { return false; } } else { QString configPath = "/etc/biometric-auth/ukui-biometric.conf"; QSettings settings(configPath, QSettings::IniFormat); qDebug() << "configure path: " << settings.fileName(); if (settings.allKeys().contains("EnableAuth")) { return settings.value("EnableAuth").toBool(); } else { QSettings sysSettings(GET_STR(CONFIG_FILE), QSettings::IniFormat); if (sysSettings.contains("EnableAuth")) return sysSettings.value("EnableAuth").toBool(); else return true; } } } /** * 获取设备列表 */ void BioDevices::getDevicesList() { /* 返回值为 i -- int 和 av -- array of variant */ QDBusMessage msg = serviceInterface->call("GetDevList"); if (msg.type() == QDBusMessage::ErrorMessage) { LOG() << msg.errorMessage(); return; } /* 设备数量 */ int deviceNum = msg.arguments().at(0).toInt(); bool bEnableBioAuth = GetBioAuthEnable(); /* 读取设备详细信息,并存储到列表中 */ QDBusArgument argument = msg.arguments().at(1).value(); QList infos; argument >> infos; deviceInfos.clear(); for (int i = 0; i < deviceNum; i++) { DeviceInfoPtr pDeviceInfo = std::make_shared(); infos.at(i).value() >> *pDeviceInfo; if (pDeviceInfo->device_available > 0) { // 设备可用 if (pDeviceInfo->biotype == REMOTE_QRCODE_TYPE && m_isIgnoreQrCode) continue; if (!bEnableBioAuth && pDeviceInfo->biotype <= BIOTYPE_VOICEPRINT) continue; deviceInfos.push_back(pDeviceInfo); } } } int BioDevices::count() { return deviceInfos.size(); } int BioDevices::GetUserDevCount(int uid) { int count = 0; QDBusMessage msg = serviceInterface->call("GetDevList"); if (msg.type() == QDBusMessage::ErrorMessage) { LOG() << msg.errorMessage(); return 0; } int deviceNum = msg.arguments().at(0).toInt(); QDBusArgument argument = msg.arguments().at(1).value(); QList infos; argument >> infos; for (int i = 0; i < deviceNum; i++) { DeviceInfoPtr pDeviceInfo = std::make_shared(); infos.at(i).value() >> *pDeviceInfo; if (pDeviceInfo->device_available > 0 && GetUserDevFeatureCount(uid, pDeviceInfo->device_id) > 0) // 设备可用 count++; } return count; } FeatureMap BioDevices::GetUserFeatures(int uid) { FeatureMap featureMap; QList qlist; int listsize; QDBusMessage result = serviceInterface->call(QStringLiteral("GetAllFeatureList"), uid, 0, -1); if (result.type() == QDBusMessage::ErrorMessage) { qWarning() << "GetDevList error:" << result.errorMessage(); return featureMap; } QList variantList = result.arguments(); listsize = variantList[0].value(); variantList[1].value() >> qlist; for (int i = 0; i < listsize; i++) { FeatureInfoPtr pFeatureInfo = std::make_shared(); qlist[i].variant().value() >> *pFeatureInfo; featureMap[pFeatureInfo->device_shortname].append(pFeatureInfo); } return featureMap; } int BioDevices::GetUserDevFeatureCount(int uid, int drvid) { QDBusMessage FeatureResult = serviceInterface->call(QStringLiteral("GetFeatureList"), drvid, uid, 0, -1); if (FeatureResult.type() == QDBusMessage::ErrorMessage) { qWarning() << "GetFeatureList error:" << FeatureResult.errorMessage(); return 0; } return FeatureResult.arguments().takeFirst().toInt(); } int BioDevices::getFeatureCount(int uid, int indexStart, int indexEnd) { int res = 0; for (int i = 0; i < deviceInfos.count(); i++) { DeviceInfoPtr deviceInfo = deviceInfos.at(i); QDBusMessage featurecount = serviceInterface->call("GetFeatureList", deviceInfo->device_id, uid, indexStart, indexEnd); if (featurecount.type() == QDBusMessage::ErrorMessage) { qWarning() << "GetFeatureList error:" << featurecount.errorMessage(); } else { res += featurecount.arguments().takeFirst().toInt(); } } return res; } QMap> BioDevices::getAllDevices() { QMap> devices; for (auto deviceInfo : deviceInfos) { if (deviceInfo->biotype == REMOTE_QRCODE_TYPE) // 终端不使用扫码 continue; if (!GetDirveIsIdle(deviceInfo->device_id)) continue; devices[deviceInfo->biotype].push_back(*deviceInfo); } return devices; } QMap> BioDevices::getUserDevices(int uid) { QMap> devices; bool isQRCodeEnable = GetQRCodeEnable(); for (auto deviceInfo : deviceInfos) { if (GetUserDevFeatureCount(uid, deviceInfo->device_id) > 0) { if (!isQRCodeEnable && deviceInfo->biotype == REMOTE_QRCODE_TYPE) // 关闭了二维码功能 continue; devices[deviceInfo->biotype].push_back(*deviceInfo); } } return devices; } QList BioDevices::getDevices(int type) { QList devices; for (auto deviceInfo : deviceInfos) { if (deviceInfo->biotype == type) devices.push_back(*deviceInfo); } return devices; } void BioDevices::setIsShowHotPlug(bool isShow) { isShowHotPlug = isShow; } bool BioDevices::getUseFirstDevice() { if (m_uniAuthService && m_uniAuthService->isActivatable()) { return m_uniAuthService->getUseFirstDevice(); } else { QSettings settings("/etc/biometric-auth/ukui-biometric.conf", QSettings::IniFormat); return settings.value("UseFirstDevice").toBool(); } } bool BioDevices::GetHiddenSwitchButton() { if (m_uniAuthService && m_uniAuthService->isActivatable()) { return m_uniAuthService->getHiddenSwitchButton(); } else { QSettings sysSettings("/etc/biometric-auth/ukui-biometric.conf", QSettings::IniFormat); if (sysSettings.contains("HiddenSwitchButton")) return sysSettings.value("HiddenSwitchButton").toBool(); else return false; } } int BioDevices::getFailedTimes() { if (m_uniAuthService && m_uniAuthService->isActivatable()) { return m_uniAuthService->getMaxFailedTimes(); } else { QSettings sysSettings("/etc/biometric-auth/ukui-biometric.conf", QSettings::IniFormat); if (sysSettings.contains("MaxFailedTimes")) return sysSettings.value("MaxFailedTimes").toInt(); else return 3; } } bool BioDevices::GetQRCodeEnable() { if (m_uniAuthService && m_uniAuthService->isActivatable()) { return m_uniAuthService->getQRCodeEnable(); } else { bool isEnable = false; QSettings sysSettings("/etc/biometric-auth/ukui-biometric.conf", QSettings::IniFormat); sysSettings.beginGroup("Functions"); if (sysSettings.allKeys().contains("EnableQRCode")) { isEnable = sysSettings.value("EnableQRCode").toBool(); } sysSettings.endGroup(); return isEnable; } } /** * ukui-greeter 1 * ukui-screensaver 1<<1 * ukui-polkit 1<<2 * sudo 1<<3 * su 1<<4 * login 1<<5 **/ bool BioDevices::GetBioAuthEnable() { if (m_uniAuthService && m_uniAuthService->isActivatable()) { bool isEnable = false; struct passwd *pwd = getpwuid(m_nUId); if (pwd) { isEnable = m_uniAuthService->getBioAuthStatus(pwd->pw_name, ENABLETYPE_BIO); } if (isEnable && !isShowHotPlug) { if (qAppName() == "polkit-ukui-authentication-agent-1") // 获取polkit开关是否打开 isEnable = m_uniAuthService->getBioAuthStatus(pwd->pw_name, ENABLETYPE_POLKIT); if (qAppName() == "bioauth") { // 获取父进程名称为sudo,su,或者login int ppid = getppid(); // 获取父进程pid QString filename = "/proc/" + QString::number(ppid) + "/cmdline"; QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Can't open the file!"; } QByteArray text = file.readAll(); file.close(); if (text.contains("sudo")) { isEnable = m_uniAuthService->getBioAuthStatus(pwd->pw_name, ENABLETYPE_SUDO); } else if (text.contains("su")) { isEnable = m_uniAuthService->getBioAuthStatus(pwd->pw_name, ENABLETYPE_SU); } else if (text.contains("login")) { isEnable = m_uniAuthService->getBioAuthStatus(pwd->pw_name, ENABLETYPE_LOGIN); } } } return isEnable; } else { bool isEnable = false; int isEnableApp = 0; QSettings sysSettings("/etc/biometric-auth/ukui-biometric.conf", QSettings::IniFormat); if (sysSettings.allKeys().contains("EnableAuth")) { isEnable = sysSettings.value("EnableAuth").toBool(); } if (isEnable && sysSettings.allKeys().contains("EnableAuthApp")) { isEnableApp = sysSettings.value("EnableAuthApp").toInt(); if (qAppName() == "polkit-ukui-authentication-agent-1") // 获取polkit开关是否打开 isEnable = isEnableApp & (1 << 2); if (qAppName() == "bioauth") { // 获取父进程名称为sudo,su,或者login int ppid = getppid(); // 获取父进程pid QString filename = "/proc/" + QString::number(ppid) + "/cmdline"; QFile file(filename); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Can't open the file!"; } QByteArray text = file.readAll(); file.close(); if (text.contains("sudo")) { isEnable = isEnableApp & (1 << 3); } else if (text.contains("su")) { isEnable = isEnableApp & (1 << 4); } else if (text.contains("login")) { isEnable = isEnableApp & (1 << 5); } } } return isEnable; } } DeviceInfoPtr BioDevices::getDefaultDevice(uid_t uid, int bioType) { if (deviceInfos.size() <= 0) return nullptr; FeatureMap mapFeatures = GetUserFeatures(uid); if (m_uniAuthService && m_uniAuthService->isActivatable()) { QString defaultDeviceName = ""; struct passwd *pwdInfo = getpwuid(uid); DeviceInfoPtr ptrDevInfo = nullptr; if (pwdInfo) { QString strDeviceName = m_uniAuthService->getDefaultDevice(pwdInfo->pw_name, bioType); qDebug() << strDeviceName; if (!strDeviceName.isEmpty()) { ptrDevInfo = findDevice(strDeviceName); if (ptrDevInfo) { int isIdle = GetDirveIsIdle(ptrDevInfo->device_id); if (isIdle && mapFeatures.contains(ptrDevInfo->device_shortname)) { defaultDeviceName = strDeviceName; } } } } if (defaultDeviceName.isEmpty()) { return nullptr; } return ptrDevInfo; } else { QString defaultDeviceName; struct passwd *pwd = getpwuid(uid); QString userConfigFile = QString(pwd->pw_dir) + "/.biometric_auth/ukui_biometric.conf"; QSettings userConfig(userConfigFile, QSettings::IniFormat); qDebug() << userConfig.fileName(); defaultDeviceName = userConfig.value(DEFAULT_DEVICE).toString(); qDebug() << defaultDeviceName; if (defaultDeviceName.isEmpty() || !findDevice(defaultDeviceName)) { QSettings sysConfig(GET_STR(CONFIG_FILE), QSettings::IniFormat); defaultDeviceName = sysConfig.value(DEFAULT_DEVICE).toString(); } if (defaultDeviceName.isEmpty() || !findDevice(defaultDeviceName)) { QString userConfigFile = QString(pwd->pw_dir) + "/.biometric_auth/ukui_biometric.conf"; QSettings userConfig(userConfigFile, QSettings::IniFormat); defaultDeviceName = userConfig.value(DEFAULT_DEVICE).toString(); } qDebug() << "default device: " << defaultDeviceName; // 终端不默认使用第一个设备 if (defaultDeviceName.isEmpty()) { return nullptr; } bool defValid = false; DeviceInfoPtr ptrDevInfo = findDevice(defaultDeviceName); if (ptrDevInfo) { int isIdle = GetDirveIsIdle(ptrDevInfo->device_id); if (isIdle && mapFeatures.contains(ptrDevInfo->device_shortname)) { defValid = true; } } if (!defValid) { ptrDevInfo = nullptr; } return ptrDevInfo; } } void BioDevices::recordAuthDrive(QString appName, int drvid, bool insert) { if (m_uniAuthService && m_uniAuthService->isActivatable()) { m_uniAuthService->recordAuthDrive(appName, drvid, insert); } } bool BioDevices::GetDirveIsIdle(int drvid) { if (m_uniAuthService && m_uniAuthService->isActivatable()) { QStringList appList = m_uniAuthService->getAuthingApp(); for (QString appName : appList) { int id = m_uniAuthService->getAuthingAppDrivd(appName); if (id == drvid) { return false; } } } return true; } DeviceInfoPtr BioDevices::getDefaultDevice(uid_t uid) { if (deviceInfos.size() <= 0) return nullptr; FeatureMap mapFeatures = GetUserFeatures(uid); if (m_uniAuthService && m_uniAuthService->isActivatable()) { QString defaultDeviceName = ""; struct passwd *pwdInfo = getpwuid(uid); DeviceInfoPtr ptrDevInfo = nullptr; if (pwdInfo) { for (auto bioType : m_listPriority) { if (bioType == REMOTE_QRCODE_TYPE) { DeviceList listDevice = findDeviceByType(bioType); for (auto device : listDevice) { int isIdle = GetDirveIsIdle(device->device_id); if (isIdle && mapFeatures.contains(device->device_shortname)) { defaultDeviceName = device->device_shortname; ptrDevInfo = device; break; } } qDebug() << "defaultDevice:" << defaultDeviceName; if (!defaultDeviceName.isEmpty()) { break; } } else { QString strDeviceName = m_uniAuthService->getDefaultDevice(pwdInfo->pw_name, bioType); qDebug() << strDeviceName; if (!strDeviceName.isEmpty()) { ptrDevInfo = findDevice(strDeviceName); if (ptrDevInfo) { int isIdle = GetDirveIsIdle(ptrDevInfo->device_id); if (isIdle && mapFeatures.contains(ptrDevInfo->device_shortname)) { defaultDeviceName = strDeviceName; break; } } } } } } if (defaultDeviceName.isEmpty()) { return nullptr; } return ptrDevInfo; } else { QString defaultDeviceName; struct passwd *pwd = getpwuid(uid); QString userConfigFile = QString(pwd->pw_dir) + "/.biometric_auth/ukui_biometric.conf"; QSettings userConfig(userConfigFile, QSettings::IniFormat); qDebug() << userConfig.fileName(); defaultDeviceName = userConfig.value(DEFAULT_DEVICE).toString(); qDebug() << defaultDeviceName; if (defaultDeviceName.isEmpty() || !findDevice(defaultDeviceName)) { QSettings sysConfig(GET_STR(CONFIG_FILE), QSettings::IniFormat); defaultDeviceName = sysConfig.value(DEFAULT_DEVICE).toString(); } if (defaultDeviceName.isEmpty() || !findDevice(defaultDeviceName)) { QString userConfigFile = QString(pwd->pw_dir) + "/.biometric_auth/ukui_biometric.conf"; QSettings userConfig(userConfigFile, QSettings::IniFormat); defaultDeviceName = userConfig.value(DEFAULT_DEVICE).toString(); } qDebug() << "default device: " << defaultDeviceName; // 终端不默认使用第一个设备 if (defaultDeviceName.isEmpty()) { return nullptr; } bool defValid = false; DeviceInfoPtr ptrDevInfo = findDevice(defaultDeviceName); if (ptrDevInfo) { if (mapFeatures.contains(ptrDevInfo->device_shortname)) { defValid = true; } } if (!defValid) { ptrDevInfo = nullptr; } return ptrDevInfo; } } QStringList BioDevices::getAllDefDevices() { QStringList listDefDevices; if (m_uniAuthService && m_uniAuthService->isActivatable()) { struct passwd *pwdInfo = getpwuid(m_nUId); if (pwdInfo) { listDefDevices = m_uniAuthService->getAllDefaultDevice(pwdInfo->pw_name); } } else { QString defaultDeviceName; struct passwd *pwd = getpwuid(m_nUId); QString userConfigFile = QString(pwd->pw_dir) + "/.biometric_auth/ukui_biometric.conf"; QSettings userConfig(userConfigFile, QSettings::IniFormat); qDebug() << userConfig.fileName(); defaultDeviceName = userConfig.value(DEFAULT_DEVICE).toString(); qDebug() << defaultDeviceName; if (defaultDeviceName.isEmpty() || !findDevice(defaultDeviceName)) { QSettings sysConfig(GET_STR(CONFIG_FILE), QSettings::IniFormat); defaultDeviceName = sysConfig.value(DEFAULT_DEVICE).toString(); } if (defaultDeviceName.isEmpty() || !findDevice(defaultDeviceName)) { QString userConfigFile = QString(pwd->pw_dir) + "/.biometric_auth/ukui_biometric.conf"; QSettings userConfig(userConfigFile, QSettings::IniFormat); defaultDeviceName = userConfig.value(DEFAULT_DEVICE).toString(); } qDebug() << "default device: " << defaultDeviceName; if (!defaultDeviceName.isEmpty()) { listDefDevices.push_back(defaultDeviceName); } } return listDefDevices; } int BioDevices::GetLastDevice(const QString &userName) { int nLastDevId = -1; QSettings sysSettings(QString(SHARE_BIOMETRIC_CONFIG_PATH).arg(userName), QSettings::IniFormat); sysSettings.beginGroup("Common"); if (sysSettings.allKeys().contains("LastDeviceId")) { nLastDevId = sysSettings.value("LastDeviceId").toInt(); } sysSettings.endGroup(); return nLastDevId; } void BioDevices::SetLastDevice(const QString &userName, int drvid) { if (drvid < 0) { return; } QString desConfPath = QString(SHARE_BIOMETRIC_CONFIG_PATH).arg(userName); QFile fileConf(desConfPath); if (fileConf.exists()) { QSettings sysSettings(desConfPath, QSettings::IniFormat); sysSettings.beginGroup("Common"); sysSettings.setValue("LastDeviceId", drvid); sysSettings.endGroup(); } else { QSettings sysSettings(desConfPath, QSettings::IniFormat); sysSettings.beginGroup("Common"); sysSettings.setValue("LastDeviceId", drvid); sysSettings.endGroup(); sysSettings.sync(); QFile file(desConfPath); file.setPermissions(QFile::WriteUser | QFile::ReadUser | QFile::WriteOther | QFile::ReadOther); } } DeviceInfoPtr BioDevices::findDevice(const int id) { for (auto deviceInfo : deviceInfos) { if (deviceInfo->device_id == id) return deviceInfo; } // qDebug() << deviceName << "doesn't exists"; return nullptr; } DeviceInfoPtr BioDevices::findDevice(const QString &deviceName) { for (auto deviceInfo : deviceInfos) { if (deviceInfo->device_shortname == deviceName) return deviceInfo; } qDebug() << deviceName << "doesn't exists"; return nullptr; } DeviceList BioDevices::findDeviceByType(int nBioType) { DeviceList listDevice; for (auto deviceInfo : deviceInfos) { if (deviceInfo->biotype == nBioType) { listDevice.append(deviceInfo); } } return listDevice; } DeviceInfoPtr BioDevices::getFirstDevice(int uid) { for (DeviceInfoPtr devInfo : deviceInfos) { if (devInfo && GetUserDevFeatureCount(uid, devInfo->device_id) > 0) { return devInfo; } } return nullptr; } QString BioDevices::bioTypeToString_tr(int type) { switch (type) { case BIOTYPE_FINGERPRINT: return tr("FingerPrint"); case BIOTYPE_FINGERVEIN: return tr("FingerVein"); case BIOTYPE_IRIS: return tr("Iris"); case BIOTYPE_FACE: return tr("Face"); case BIOTYPE_VOICEPRINT: return tr("VoicePrint"); case LOGINOPT_TYPE_GENERAL_UKEY: return tr("Ukey"); case REMOTE_QRCODE_TYPE: return tr("QRCode"); } return QString(); } DeviceList BioDevices::GetDevList() { return deviceInfos; } StatusReslut BioDevices::UpdateStatus(int drvid) { StatusReslut status; QDBusMessage result = serviceInterface->call(QStringLiteral("UpdateStatus"), drvid); if (result.type() == QDBusMessage::ErrorMessage) { qWarning() << "UpdateStatus error:" << result.errorMessage(); status.result = -1; return status; } status.result = result.arguments().at(0).toInt(); status.enable = result.arguments().at(1).toInt(); status.devNum = result.arguments().at(2).toInt(); status.devStatus = result.arguments().at(3).toInt(); status.opsStatus = result.arguments().at(4).toInt(); status.notifyMessageId = result.arguments().at(5).toInt(); return status; } ukui-biometric-auth/bioauth/src/biodeviceswidget.ui0000664000175000017500000000273615167732630021512 0ustar fengfeng BioDevicesWidget 0 0 530 99 Form 0 0 0 0 0 36 16777215 36 ukui-biometric-auth/bioauth/src/bioauthwidget.ui0000664000175000017500000001057015167732630021024 0ustar fengfeng BioAuthWidget 0 0 404 282 Form 20 10 Qt::Horizontal 40 20 130 130 128 128 Qt::AlignCenter Qt::Horizontal 40 20 0 20 Qt::AlignCenter true 0 20 Qt::AlignCenter true 8 Qt::Horizontal 40 20 80 28 QPushButton:hover{border:none;color:#3E6CE5;}QPushButton:pressed{border:none;} QPushButton{font-size:14px;} Retry Qt::Horizontal 40 20 ukui-biometric-auth/bioauth/src/giodbus.cpp0000664000175000017500000000544015167732630017766 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "giodbus.h" #include #include #include int get_server_gvariant_stdout (int drvid) { GDBusMessage *method_call_message; GDBusMessage *method_reply_message; GUnixFDList *fd_list; GError **error = NULL; gint fd,dup_fd; const gchar * response; fd = -1; dup_fd = -1; method_call_message = NULL; method_reply_message = NULL; GDBusConnection *con = g_bus_get_sync(G_BUS_TYPE_SYSTEM,NULL,NULL); method_call_message = g_dbus_message_new_method_call ("org.ukui.Biometric", "/org/ukui/Biometric", "org.ukui.Biometric", "GetFrameFd"); g_dbus_message_set_body (method_call_message, g_variant_new ("(i)", drvid)); method_reply_message = g_dbus_connection_send_message_with_reply_sync (con, method_call_message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, /* out_serial */ NULL, /* cancellable */ error); if (method_reply_message == NULL) goto out; if (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_ERROR) { g_dbus_message_to_gerror (method_reply_message, error); goto out; } //g_print("%s",g_dbus_message_print(method_reply_message,0)); fd_list = g_dbus_message_get_unix_fd_list(method_reply_message); fd = g_unix_fd_list_get(fd_list,0,error); //g_print("get fd : %d\n", fd); dup_fd = dup(fd); //g_print("dup fd : %d\n", dup_fd); out: g_object_unref (method_call_message); g_object_unref (method_reply_message); return fd; } ukui-biometric-auth/bioauth/CMakeLists.txt0000664000175000017500000000573515167732644017613 0ustar fengfeng# 根据Qt版本使用相应的wrap函数 if(QT_VERSION_MAJOR EQUAL 6) pkg_check_modules(QGS REQUIRED gsettings-qt6) qt6_wrap_ui(BioAuthWidgets_SRC src/bioauthwidget.ui src/biodeviceswidget.ui ) qt6_wrap_cpp(BioAuth_SRC include/bioauth.h include/biodevices.h include/uniauthservice.h ) qt6_wrap_cpp(BioAuthWidgets_SRC include/bioauthwidget.h include/biodeviceswidget.h include/giodbus.h include/loginoptionswidget.h ) else() pkg_check_modules(QGS REQUIRED gsettings-qt) qt5_wrap_ui(BioAuthWidgets_SRC src/bioauthwidget.ui src/biodeviceswidget.ui ) qt5_wrap_cpp(BioAuth_SRC include/bioauth.h include/biodevices.h include/uniauthservice.h ) qt5_wrap_cpp(BioAuthWidgets_SRC include/bioauthwidget.h include/biodeviceswidget.h include/giodbus.h include/loginoptionswidget.h ) endif() set(BioAuth_SRC ${BioAuth_SRC} src/bioauth.cpp src/biodevices.cpp src/biotypes.cpp src/uniauthservice.cpp ) set(BioAuthWidgets_SRC ${BioAuthWidgets_SRC} src/bioauthwidget.cpp src/biodeviceswidget.cpp src/giodbus.cpp src/loginoptionswidget.cpp ) # 根据Qt版本设置包含目录和链接库 if(QT_VERSION_MAJOR EQUAL 6) include_directories( ${Qt6Core_INCLUDE_DIRS} ${Qt6Widgets_INCLUDE_DIRS} ${Qt6DBus_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS} ${GIOUNIX2_INCLUDE_DIRS} ${QGS_INCLUDE_DIRS} include ../common ) add_library(BioAuth STATIC ${BioAuth_SRC}) target_link_libraries(BioAuth Qt6::Core Qt6::DBus Qt6::Svg) add_library(BioAuthWidgets STATIC ${BioAuthWidgets_SRC}) target_link_libraries(BioAuthWidgets BioAuth Qt6::Widgets ${OpenCV_LIBS} ${GIOUNIX2_LIBRARIES} ${QGS_LIBRARIES}) else() include_directories( ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5DBus_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS} ${GIOUNIX2_INCLUDE_DIRS} ${QGS_INCLUDE_DIRS} include ../common ) add_library(BioAuth STATIC ${BioAuth_SRC}) target_link_libraries(BioAuth Qt5::Core Qt5::DBus Qt5::Svg) add_library(BioAuthWidgets STATIC ${BioAuthWidgets_SRC}) target_link_libraries(BioAuthWidgets BioAuth Qt5::Widgets ${OpenCV_LIBS} ${GIOUNIX2_LIBRARIES} ${QGS_LIBRARIES}) endif() #add_library(BioAuth OBJECT ${BioAuth_SRC}) #add_library(BioAuthWidgets OBJECT ${BioAuth_SRC} ${BioAuthWidgets_SRC}) file(GLOB ts_files i18n_ts/*.ts) # 根据Qt版本使用相应的翻译函数 if(QT_VERSION_MAJOR EQUAL 6) qt6_add_translation(qm_files ${ts_files}) else() qt5_add_translation(qm_files ${ts_files}) endif() add_custom_target(bioauth_i18n DEPENDS ${qm_files} SOURCES ${ts_files}) add_dependencies(BioAuth bioauth_i18n) install(FILES ${qm_files} DESTINATION ${UKUI_BIOMETRIC_DIR}/i18n_qm) ukui-biometric-auth/bioauth/i18n_ts/0000775000175000017500000000000015167732644016326 5ustar fengfengukui-biometric-auth/bioauth/i18n_ts/ru.ts0000664000175000017500000000776515167732644017343 0ustar fengfeng BioAuthWidget Form форма TextLabel TextLabel More Больше Retry Retry Password пароль %1 too many unsuccessful attempts,please enter password. %1 authentication failure,there are still %2 remaining opportunities Please use wechat to scan the code BioDevices FingerPrint FingerPrint FingerVein FingerVein Iris Ирис Face Лицо VoicePrint Voiceprint Unplugging of %1 device detected %1 device insertion detected biometric QRCode Biometric Manager Ukey BioDevicesWidget Form форма Device types: Типы устройств: Back назад OK ОК LoginOptionsWidget Login Options Password пароль ukui-biometric-auth/bioauth/i18n_ts/ky.ts0000664000175000017500000001702115167732644017322 0ustar fengfeng BioAuthWidget Form جادىبال More 更多 Retry قايرا قايرا سىنوو Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password 密码 Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. جەڭىلۉۉ بولۇش ىرەت سانى ارتىقچا كۅپ بولۇپ كەتتى، جاشىرۇۇن نومۇردۇ كىرگىزىڭ %1 authentication failure,there are still %2 remaining opportunities تولۇمدۇۇلۇق دالىلدۅ جەڭىلۉۉ بولدۇ ، داعى ەكى ىرەت وڭۇتۇڭۇز قالدى Please use wechat to scan the code ئۈندىداردا ىسكاننىردوو BioDevices Unplugging of %1 device detected تەكشەرىپ بايقاعان 1 اسپاپتى تارتىپ چىعارۇۇ %1 device insertion detected 1 جابدۇۇسۇنۇن كىرگىزىلگەندىگىن تەكشەرىپ چىعىش Biometric Manager بىيولوگىيەلىك ۅزگۅچۅلۉگۉ باشقارىش قۇرالى biometric بىيولوگىيەلىك ۅزگۅچۅلۉك FingerPrint بارماق ئزى FingerVein بارماق ۋېنا تومۇرى Iris كۅز ئالمىسى رەڭدار پەردىسى Face جۉز VoicePrint قووپسۇزدۇق شىڧىرلىق اچقىچى Ukey ەسەپتىك كۉبۅلۉك QRCode ەكىلىك قۇپۇيا نومۇر Wechat 微信 BioDevicesWidget Form جادىبال Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options كىرۉۉ تاندالمالارى Password جاشىرۇۇن اچقىچ Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 ukui-biometric-auth/bioauth/i18n_ts/zh_CN.ts0000664000175000017500000001547615167732644017714 0ustar fengfeng BioAuthWidget Form More 更多 Retry 重试 Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password 密码 Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 authentication failure,there are still %2 remaining opportunities Please use wechat to scan the code 请使用微信扫码 BioDevices Unplugging of %1 device detected 检测到%1设备拔出 %1 device insertion detected 检测到%1设备插入 Biometric Manager 生物特征管理工具 biometric 生物特征 FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸识别 VoicePrint 声纹 Ukey 安全密钥 QRCode 二维码 Wechat 微信 BioDevicesWidget Form Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options 登录选项 Password 密码 Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 ukui-biometric-auth/bioauth/i18n_ts/kk.ts0000664000175000017500000001672215167732644017313 0ustar fengfeng BioAuthWidget Form كەستە More 更多 Retry قاتە قاتە سىناۋ Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password 密码 Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. جەڭىلىپ بولۋ رەت سانى اسقىن كوپ بولىپ كەتتى، قۇپيا نۇمىردى كىرگىزىڭىز %1 authentication failure,there are still %2 remaining opportunities سالاۋاتىن دالەلدەۋ جەڭىلىپ قالدى، جانە ەكٸ رەت ورايڭىز قالدى Please use wechat to scan the code ئۈندىداردا كەسكىندەۋىش BioDevices Unplugging of %1 device detected تەكسەرٸپ بايقاعان 1 اسبابٸن تارتىپ شىعارماق %1 device insertion detected 1 اسبابٸتٸڭ كىرگىزىلگەنىن تەكسەرٸپ شىقپاق Biometric Manager بىيولوگىيەلىك ەرەكشەلىكتى باسقارۋ قۇرالى biometric بىيولوگىيەلىك ەرەكشەلىك FingerPrint بارماقشى ٴٸزٸ FingerVein بارماقشى ۋېنا تومۇرى Iris كوز ئالمىسى تۇستى پەردىسى Face جۇز VoicePrint حاۋىپسىزدىك شىڧىرلىق يٸندەكٸسٸ Ukey ساندىق كۋالىك QRCode ەكٸلٸك رازمەر Wechat 微信 BioDevicesWidget Form كەستە Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options كىرۋ تالدانبالارٸ Password قۇپيا كىلت Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 ukui-biometric-auth/bioauth/i18n_ts/tr.ts0000664000175000017500000001410015167732644017317 0ustar fengfeng BioAuthWidget Form More Daha Fazla Retry Yeniden Dene Password Parola Current Device: Şuanki Aygıt: %1 too many unsuccessful attempts,please enter password. %1 authentication failure,there are still %2 remaining opportunities Please use wechat to scan the code BioDevices Unplugging of %1 device detected %1 device insertion detected Biometric Manager biometric FingerPrint Parmak İzi FingerVein Damar İzi Iris Göz Face Yüz VoicePrint Ses İzi Ukey QRCode BioDevicesWidget Form Device types: Aygıt türü: Back Geri OK Tamam FingerPrint Parmak İzi LoginOptionsWidget Login Options Password Parola QObject FingerPrint Parmak İzi FingerVein Damar İzi Iris Göz Face Yüz VoicePrint Ses İzi ukui-biometric-auth/bioauth/i18n_ts/bo.ts0000664000175000017500000001121615167732644017277 0ustar fengfeng BioAuthWidget Form Retry %1 too many unsuccessful attempts,please enter password. %1 authentication failure,there are still %2 remaining opportunities Please use wechat to scan the code BioDevices Unplugging of %1 device detected %1 device insertion detected Biometric Manager biometric FingerPrint FingerVein Iris Face VoicePrint Ukey QRCode BioDevicesWidget Form LoginOptionsWidget Login Options Password ukui-biometric-auth/bioauth/i18n_ts/ug.ts0000664000175000017500000001672315167732644017322 0ustar fengfeng BioAuthWidget Form جەدۋەل More 更多 Retry قايتا قايتا تىرشىش Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password 密码 Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. مەغلۇپ بولۇش قېتىم سانى زىيادە كۆپ بولۇپ كەتتى، مەخپىي نومۇرنى كىرگۈزۈڭ %1 authentication failure,there are still %2 remaining opportunities سالاھىيىتىنى دەلىللەش مەغلۇپ بولدى، يەنە ئىككى قېتىم پۇرسىتىڭىز قالدى Please use wechat to scan the code ئۈندىداردا سىكانىرلاڭ BioDevices Unplugging of %1 device detected تەكشۈرۈپ بايقىغان 1 ئۈسكۈنىنى تارتىپ چىقارماق %1 device insertion detected 1 ئۈسكۈنىنىڭ كىرگۈزۈلگەنلىكىنى تەكشۈرۈپ چىقماق Biometric Manager بىئولەگىيەلىك ئالاھىدىلىكنى باشقۇرۇش قورالى biometric بىئولوگىيەلىك ئالاھىدىلىك FingerPrint بارماق ئىزى FingerVein بارماقVein Iris ئېرسى Face يۈز VoicePrint بىخەتەرلىك شىڧىرلىق ئاچقۇچى Ukey رەقەملىك گۇۋاھنامە QRCode ئىككىلىك كود Wechat 微信 BioDevicesWidget Form جەدۋەل Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options كىرىش تاللانمىلىرى Password مەخپىي ئاچقۇچ Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 ukui-biometric-auth/bioauth/i18n_ts/pt.ts0000664000175000017500000000773615167732644017336 0ustar fengfeng BioAuthWidget Form Formato TextLabel TextLabel More Mais Retry Tente novamente Password Senha %1 too many unsuccessful attempts,please enter password. %1 authentication failure,there are still %2 remaining opportunities Please use wechat to scan the code BioDevices FingerPrint Impressão digital FingerVein FingerVein Iris Íris Face Cara VoicePrint VoicePrint Unplugging of %1 device detected %1 device insertion detected biometric QRCode Biometric Manager Ukey BioDevicesWidget Form Formato Device types: Tipos de dispositivos: Back Costas OK Está bem LoginOptionsWidget Login Options Password Senha ukui-biometric-auth/bioauth/i18n_ts/bo_CN.ts0000664000175000017500000001263515167732644017665 0ustar fengfeng BioAuthWidget Form རེའུ་མིག More དེ་ལས་མང་བ། Retry ཡང་བསྐྱར་ཚོད་ལེན། Current Device: 当前设备: Password གསང་ཨང་། TextLabel ཡིག་རྐྱང་ཕྲེང་བ། %1 too many unsuccessful attempts,please enter password. %1ལ་ལེགས་འགྲུབ་མ་བྱུང་བའི་ཚོད་ལྟ་མང་དྲགས་པས་གསང་གྲངས་ནང་འཇུག་གནང་རོགས། %1 authentication failure,there are still %2 remaining opportunities %1 བདེན་དཔང་ར་སྤྲོད་བྱེད་མ་ཐུབ་ན། ད་དུང་%2ལྷག་པའི་གོ་སྐབས་ཡོད། Please use wechat to scan the code སྐད་འཕྲིན་གྱི་ཨང་བཤེར་སྤྱོད་ཅིག BioDevices Face མིའི་གདོང་ངོས་འཛིན། Iris འཇའ་སྐྱི། biometric སྐྱེ་དངོས་སྒྲིག་ཆས། VoicePrint སྒྲ་རིམ། Unplugging of %1 device detected ཞིབ་དཔྱད་ཚད་ལེན་བྱས་པའི་%1སྒྲིག་ཆས་ཀྱི་ཁ་པར་རྒྱག་པ། %1 device insertion detected %1སྒྲིག་ཆས་ནང་དུ་བཅུག་ནས་ཞིབ་དཔྱད་ཚད་ལེན་བྱས་པ་རེད། FingerPrint མཛུབ་རིས། FingerVein མཛུབ་སྡོད་རྩ། Biometric Manager སྐྱེ་དངོས་ཁྱད་རྟགས་དོ་དམ་ཡོ་བྱད། QRCode རྩ་གཉིས་ཨང་གྲངས། Ukey བདེ་འཇགས་གསང་ལྡེ་ BioDevicesWidget OK གཏན་འཁེལ་བྱེད་པ། Back ཕྱིར་འཐེན། Form རེའུ་མིག Device types: 设备类型: LoginOptionsWidget Login Options ཐོ་འགོད་ཀྱི་བསལ་འདེམས་ཀྱི་དབང་ཆ། Password ཕར་འགྲོ་ཚུར་འོང་བྱེད་མཁན། ukui-biometric-auth/bioauth/i18n_ts/vi.ts0000664000175000017500000001604315167732644017320 0ustar fengfeng BioAuthWidget Form More 更多 Retry Thử lại Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password 密码 Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 quá nhiều lần thử không thành công, vui lòng nhập mật khẩu. %1 authentication failure,there are still %2 remaining opportunities %1 xác thực thất bại, còn %2 lần thử Please use wechat to scan the code Vui lòng sử dụng WeChat để quét mã BioDevices Unplugging of %1 device detected Phát hiện rút phích cắm%1 thiết bị %1 device insertion detected Phát hiện thiết bị %1 đã cắm vào Biometric Manager Trình quản lý sinh trắc học biometric Đặc điểm sinh trắc học FingerPrint Vân tay FingerVein Tĩnh mạch ngón tay Iris Mống mắt Face Mặt VoicePrint Sinh trắc giọng nói Ukey Ukey QRCode Mã QR Wechat 微信 BioDevicesWidget Form Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options Tùy chọn đăng nhập Password Mật khẩu Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 ukui-biometric-auth/bioauth/i18n_ts/mn.ts0000664000175000017500000002030515167732644017310 0ustar fengfeng BioAuthWidget Form ᠬᠡᠯᠪᠡᠷᠢ More 更多 Retry ᠳᠠᠬᠢᠨ ᠳᠤᠷᠰᠢᠬᠤ Too many unsuccessful attempts,please enter password. 验证失败达最大次数,请使用密码解锁 Bioauth authentication failed, you still have %1 verification opportunities 生物认证失败,您还有%1次尝试机会 Password ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ Current Device: 当前设备: %1 too many unsuccessful attempts,please enter password. %1 ᠢᠯᠠᠭᠳᠠᠭᠰᠠᠨ ᠲᠤᠷᠰᠢᠬᠤ ᠤᠳᠠᠭ᠎ᠠ ᠲᠣᠭ᠎ᠠ ᠬᠡᠳᠦ ᠣᠯᠠᠨ᠂ ᠨᠢᠭᠤᠴᠠ ᠺᠣᠳ᠋ ᠣᠷᠣᠭᠤᠯᠤᠭᠠᠷᠠᠢ᠃ %1 authentication failure,there are still %2 remaining opportunities %1 ᠪᠡᠶ᠎ᠡ᠎ᠶ᠋ᠢᠨ ᠬᠢᠷᠢ᠎ᠶ᠋ᠢᠨ ᠰᠢᠯᠭᠠᠨ ᠪᠠᠲᠤᠯᠠᠯᠲᠠ ᠢᠯᠠᠭᠳᠠᠪᠠ ᠂ ᠮᠥᠨ %2 ᠦᠯᠡᠳᠡᠬᠦ ᠲᠣᠬᠢᠶᠠᠯ ᠪᠣᠢ Please use wechat to scan the code ᠸᠢᠴᠠᠲ᠎ᠢ᠋ᠶ᠋ᠠᠷ ᠦᠰᠦᠭ ᠰᠢᠷᠪᠢᠬᠦ ᠪᠣᠯᠪᠠᠤ BioDevices Unplugging of %1 device detected %1 ᠳᠦᠬᠦᠬᠡᠷᠦᠮᠵᠢ ᠰᠤᠭᠤᠯᠤᠭᠳᠠᠭᠰᠠᠨ ᠢ᠋ ᠪᠠᠢᠴᠠᠭᠠᠵᠤ ᠤᠯᠪᠠ %1 device insertion detected %1 ᠳᠦᠬᠦᠬᠡᠷᠦᠮᠵᠢ ᠵᠢ ᠬᠠᠪᠴᠢᠭᠤᠯᠤᠭᠰᠠᠨ ᠢ᠋ ᠬᠢᠨᠠᠨ ᠪᠠᠢᠴᠠᠭᠠᠵᠤ ᠤᠯᠪᠠ Biometric Manager ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ᠎ᠤ᠋ᠨ ᠣᠨᠴᠠᠯᠢᠭ ᠬᠠᠮᠢᠶᠠᠷᠤᠯᠲᠠ᠎ᠶ᠋ᠢᠨ ᠪᠠᠭᠠᠵᠢ biometric ᠪᠢᠤᠯᠤᠬᠢ ᠵᠢᠨ ᠣᠨᠴᠠᠯᠢᠭ FingerPrint ᠬᠤᠷᠤᠭᠤᠨ ᠤᠷᠤᠮ FingerVein ᠬᠤᠷᠤᠭᠤᠨ ᠨᠠᠮᠵᠢᠭᠤᠨ ᠰᠤᠳᠠᠰᠤ Iris ᠰᠣᠯᠣᠩᠭ᠎ᠠ ᠪᠦᠷᠬᠦᠭᠦᠯ Face ᠴᠢᠷᠠᠢ ᠪᠡᠷ ᠲᠠᠨᠢᠬᠤ VoicePrint ᠳᠠᠭᠤᠨ ᠣᠷᠣᠮ Ukey ᠠᠶᠤᠯᠭᠦᠢ ᠨᠢᠭᠤᠴᠠ ᠲᠦᠯᠬᠢᠭᠦᠷ ukey ᠠᠶᠤᠯᠭᠦᠢ ᠨᠢᠭᠤᠴᠠ ᠲᠦᠯᠬᠢᠭᠦᠷ QRCode ᠬᠤᠶᠠᠷ ᠬᠡᠮᠵᠢᠯᠳᠡᠳᠦ ᠺᠤᠳ᠋ Wechat 微信 BioDevicesWidget Form ᠬᠡᠯᠪᠡᠷᠢ Device types: 设备类型: Back 返回 OK 确定 FingerPrint 指纹 LoginOptionsWidget Login Options ᠨᠡᠪᠳᠡᠷᠡᠬᠦ ᠰᠤᠩᠭᠤᠭᠳᠠᠬᠤᠨ Password ᠨᠢᠭᠤᠴᠠ ᠺᠤᠳ᠋ Wechat 微信 Biometric 生物识别 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 ukui-biometric-auth/bioauth/i18n_ts/fr.ts0000664000175000017500000000775415167732644017322 0ustar fengfeng BioAuthWidget Form Forme TextLabel TextLabel More Plus Retry Recommencez Password Mot de passe %1 too many unsuccessful attempts,please enter password. %1 authentication failure,there are still %2 remaining opportunities Please use wechat to scan the code BioDevices FingerPrint Empreinte digitale FingerVein FingerVein Iris Iris Face Visage VoicePrint VoicePrint Unplugging of %1 device detected %1 device insertion detected biometric QRCode Biometric Manager Ukey BioDevicesWidget Form Forme Device types: Types d'appareils: Back Arrière OK D'accord LoginOptionsWidget Login Options Password Mot de passe ukui-biometric-auth/bioauth/i18n_ts/es.ts0000664000175000017500000000775715167732644017325 0ustar fengfeng BioAuthWidget Form Formar TextLabel TextLabel More Más Retry Procesar de nuevo Password Contraseña %1 too many unsuccessful attempts,please enter password. %1 authentication failure,there are still %2 remaining opportunities Please use wechat to scan the code BioDevices FingerPrint Huella dactilar FingerVein FingerVein Iris Iris Face Cara VoicePrint Impresión de voz Unplugging of %1 device detected %1 device insertion detected biometric QRCode Biometric Manager Ukey BioDevicesWidget Form Formar Device types: Tipos de dispositivos: Back Espalda OK DE ACUERDO LoginOptionsWidget Login Options Password Contraseña ukui-biometric-auth/bioauth/i18n_ts/zh_HK.ts0000664000175000017500000005241615167732644017711 0ustar fengfeng BioAuthWidget Retry 重试 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 Please use wechat to scan the code 请使用微信扫码 BioDevices FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Wechat 微信 QRCode 二维码 FullScreenBackground Authentication 授權 LoginOptionsWidget Login Options 登录选项 Wechat 微信 MainWindow Authentication 授權 Fingerprint authentication failed, you still have %1 verification opportunities 指纹验证失败,您还有%1次尝试机会 Form More 更多 Restart 重新开始 Password 密码 Biometric 使用生物識別 use password 使用密碼驗證 DeviceType: 设备类型: Back 返回 Details 详细 Action Id: 动作: Description: 描述: Polkit.subject-pid: Polkit.subject-pid: Retry 重试 Device types: 设备类型: Vendor: 发行商: Action: 动作: Polkit.caller-pid: Polkit.caller-pid: Cancel 取消 Authenticate 授權 Use password 使用密碼驗證 Auth 授权 Too many unsuccessful attempts,please enter password. 指纹验证失败达最大次数,请使用密码解锁 %1 authentication failure,there are still %2 remaining opportunities %1认证失败,还剩%2次尝试机会 %1 too many unsuccessful attempts,please enter password. %1验证失败达最大次数,请使用密码登录 in authentication, please wait... 认证中,请稍等... Please try again in %1 minutes. 請%1分鐘后再試 Please try again in %1 seconds. 請%1秒後再試 Account locked permanently. 帳號已被永久鎖定 Password cannot be empty 密碼不能為空 Failed to verify %1, please enter password. 验证%1失败,请输入密码. Unable to verify %1, please enter password. 无法验证%1,请输入密码. Failed to verify %1, you still have %2 verification opportunities 驗證%1失敗,您還有%2次嘗試機會 An application is attempting to perform an action that requires privileges. Authentication is required to perform this action. 一个程序正试图执行一个需要特权的动作。要求授权以执行该动作。 Password: 密碼: Please enter your password or enroll your fingerprint 請輸入密碼或者錄入指紋 wechat 微信 Use the bound %1 scanning code to authorization %1掃碼以授權 Abnormal network 網路異常 This operation requires the administrator's authorization. Please enter your password to allow this operation. 本次操作需要通過管理員的授權才能繼續執行,請輸入密碼以允許本次操作。 _Password: 密碼: _Password: 密碼: Authentication failed, please try again. 認證失敗,請重試。 days left 天后解鎖 Biometric/code scan authentication failed too many times, please enter the password. 生物/扫码验证失败达最大次数,请使用密码解锁. Bioauth/code scan authentication failed, you still have %1 verification opportunities 生物/扫码验证失败,您还有%1次尝试机会 Failed to verify %1, please enter password to unlock 驗證%1失敗,請輸入密碼解鎖 Unable to verify %1, please enter password to unlock 無法驗證%1,請輸入密碼解鎖 NET Exception 网络异常 A program is attempting to perform an action that requires privileges.It requires authorization to perform the action. 一個程式正試圖執行一個需要特權的動作,要求授權以執行該動作。 Input Password 輸入密碼 Insert the ukey into the USB port 請將安全金鑰插入USB埠 Enter the ukey password 輸入安全金鑰密碼 Close 關閉 Enter the two-factor authentication (2FA) OTP token for the administrator "%1" Enter the two-factor authentication (2FA) OTP dynamic token for the user "%1" Enter the two-factor authentication (2FA) security key for the administrator "%1" Enter the two-factor authentication (2FA) security key for the user "%1" Facial recognition to authorization 識別人臉以授權 Fingerprint recognition to authorization 識別指紋以授權 Voiceprint recognition to authorization 識別聲紋以授權 Finger veins recognition to authorization 識別指靜脈以授權 Iris recognition to authorization 識別虹膜以授權 Use the bound wechat scanning code to authorization 微信掃碼以授權 Acquisition failure 獲取失敗 hours left 小時後解鎖 minutes left 分鐘後解鎖 seconds left 秒後解鎖 Input your password to authentication 輸入密碼以認證 Verify face recognition or enter password to unlock 驗證人臉識別或輸入密碼解鎖 Press fingerprint or enter password to unlock 按壓指紋或輸入密碼解鎖 Verify voiceprint or enter password to unlock 驗證聲紋或輸入密碼解鎖 Verify finger vein or enter password to unlock 驗證指靜脈或輸入密碼解鎖 Verify iris or enter password to unlock 驗證虹膜或輸入密碼解鎖 Use the bound wechat scanning code or enter the password to unlock 使用綁定的微信掃碼或輸入密碼解鎖 Use the bound wechat scanning code or enter the password to log in 使用绑定的微信扫码或输入密码登录 Account locked, 帳戶已鎖定, Authentication failed, please try again 认证失败,请重试 PolkitListener Another client is already authenticating, please try again later. 有另外一個用戶端正在認證,請稍後重試。 Authentication failure, please try again. 認證失敗,請重試。 Password input error! 密碼輸入錯誤! Account locked %1 minutes due to %2 fail attempts 账户锁定%1分钟由于%2次错误尝试 Authentication failure,there are still %1 remaining opportunities 认证失败,还剩余%1次尝试机会 QObject FingerPrint 指纹 FingerVein 指静脉 Iris 虹膜 Face 人脸 VoicePrint 声纹 Cancel 取消 ukui-biometric-auth/bioauth/include/0000775000175000017500000000000015167732644016464 5ustar fengfengukui-biometric-auth/bioauth/include/loginoptionswidget.h0000664000175000017500000001463715167732644022600 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef LOGINOPTIONSWIDGET_H #define LOGINOPTIONSWIDGET_H #include #include #include "bioauth.h" #include "biodevices.h" #include class QLabel; class QButtonGroup; class QHBoxLayout; class QVBoxLayout; class QToolButton; class QTimer; typedef enum { BioT_FingerPrint, /** 指纹 **/ BioT_FingerVein, /** 指静脉 **/ BioT_Iris, /** 虹膜 **/ BioT_Face, /** 人脸 **/ BioT_VoicePrint, /** 声纹 **/ UniT_KCM, /** 安全管控 **/ UniT_General_Ukey, /** 普通的Ukey **/ UniT_Advanced_Ukey, /** 高阶的Ukey **/ UniT_Remote, /** 远程账户 **/ }Bio_Type; class LoginOptionsWidget : public QWidget { Q_OBJECT public: explicit LoginOptionsWidget(QWidget *parent = nullptr); virtual ~LoginOptionsWidget(); bool getCurLoginOpt(int& nLoginOptType, int& nDrvId); unsigned getLoginOptCount(); DeviceInfoPtr getFirstDevInfo(); int convertDeviceType(int nDevType); void updateUIStatus(bool update, int nPreOptType = -1); void updateUkeyUIStatus(int type); void setUser(int uid); void setCurrentDevice(int drvid); void setCurrentDevice(const QString &deviceName); void setCurrentDevice(const DeviceInfoPtr &pDeviceInfo); DeviceInfoPtr findDeviceById(int drvid); DeviceInfoPtr findDeviceByName(const QString &name); void setDeviceDisable(int nDevId, bool bDisable = true); bool isDeviceDisable(int nDevId); void lockStatusChanged(bool locked); /** * @brief 获取默认设备 * @return */ QString GetDefaultDevice(uid_t uid); QString GetDefaultDevice(uid_t uid,int bioType); /** * @brief 进行生物识别认证 * @param deviceInfo 使用的设备 * @param uid 待认证的用户id */ void startAuth(DeviceInfoPtr device, int uid); /** * @brief 终止生物识别认证 */ void stopAuth(); /** * @brief 是否正在认证 * @return */ bool isAuthenticating() { return m_isInAuth; } QPixmap loadSvg(QString path, QString color, int size); void SetExtraInfo(QString extra_info,QString info_type); bool getHasUkeyOptions(); void setSelectedPassword(); // 设置所有生物识别的禁用状态 void setAllDeviceDisable(bool bDisable = true); void startBioWaiting(unsigned uCurLoginOptType); void stopBioWaiting(bool isDisable = false); public slots: void readDevicesInfo(); void onIdentifyComplete(int uid, bool ret, int retErrNo); void onAuthFinished(); void onStatusChanged(int drvid, const QString &message); void onFrameWritten(int drvid); void onUSBDeviceCountChange(int newNum); void onOptionSelected(int nIndex); void setQRCodeMsg(QString strMsg); void setQRCode(QImage& imgQRCode); void setFaceImg(QImage& imgFace, int nStatus = 0); signals: void notifyOptionsChange(unsigned uOptionsCount); void optionSelected(unsigned uLoginOptType, const DeviceInfoPtr &deviceInfo); void updateImage(QImage img); // nStatus -1 dbus错误,0 无错误,1 超时,2 其他错误 void authComplete(uid_t uid, bool bResult, int nStatus); void updateAuthMsg(QString strMsg); void updateWndSize(unsigned uLoginOptType, unsigned uLoginOptSize); private: void initUI(); void initConnections(); void initStyleTheme(); void addOptionButton(unsigned uLoginOptType, int nDrvId, QString strDrvName); void clearOptionButtons(); void updateOptionButtons(); void startAuth_(); QPixmap PixmapToRound(const QPixmap &src, int radius); QPixmap scaledPixmap(int width, int height, QString url); QPixmap drawSymbolicColoredPixmap(QPixmap &source, QString cgColor); void updatePixmap(); QPixmap scaledSmoothPixmap(const QPixmap &src, int nWidth, int nHeight); private: BioAuth *m_biomericProxy = nullptr; BioDevices *m_bioDevices = nullptr; DeviceMap m_mapDevices; unsigned m_curLoginOptType = LOGINOPT_TYPE_PASSWORD; int m_uid = -1; QString m_strUserName; DeviceInfoPtr m_curDevInfo = nullptr; // 当前选择的设备信息 int m_dupFD = -1; // 透传的图像文件句柄 bool m_isInAuth; // 是否正在验证 bool m_isStopped; // 是否被强制终止 QTimer *m_retrytimer = nullptr; // 重试定时器 // UI QVBoxLayout *m_layoutMain = nullptr; QHBoxLayout *m_layoutOptBtns = nullptr; QHBoxLayout *m_layoutImage = nullptr; QLabel *m_labelOptTitle = nullptr; QButtonGroup *m_btnGroup = nullptr; QList m_listDriveId; QMap m_mapOptBtns; QWidget *m_widgetImage = nullptr; QLabel *m_labelFace = nullptr; QLabel *m_labelFaceLoad = nullptr; QLabel *m_labelQRCode = nullptr; // 二维码图标 QLabel *m_labelQRCodeMsg = nullptr; // 二维码状态消息提示 QLabel *m_labelQRCodeTip = nullptr; QMap> m_mapDisableDev; bool is_Lock = false; QPixmap m_waitingPixmap; QTimer *w_timer; bool isShowUkey = false; // 指纹、指静脉、虹膜、声纹识别动图 QLabel *m_labelBioWaiting = nullptr; // 指纹、指静脉、虹膜、声纹识别动图提示 QTimer *m_timerBioWaiting = nullptr; // 指纹、指静脉、虹膜、声纹识别动图切换定时器 int m_nBioWaitingFrame = 0; // 当前显示的动图帧 int m_nCurBioWaitingType = -1; // 当前显示的动图类型 QGSettings *m_styleSettings = nullptr; QString m_strThemeName = ""; }; #endif // LOGINOPTIONSWIDGET_H ukui-biometric-auth/bioauth/include/bioauth.h0000664000175000017500000000534515167732630020272 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef BIOAUTH_H #define BIOAUTH_H #include #include "biotypes.h" class QDBusInterface; /*! * \brief The BioAuth class * 负责真正的生物识别操作,通过startAuth开始认证, * 认证完成后会发出携带结果的authComplete信号 */ class BioAuth : public QObject { Q_OBJECT public: explicit BioAuth(qint32 uid, const DeviceInfoPtr deviceInfo, QObject *parent = nullptr); explicit BioAuth(QObject *parent = nullptr); ~BioAuth(); void setDevice(const DeviceInfoPtr deviceInfo); void setUid(qint32 uid); DeviceInfoPtr getDevice(); void startAuth(); void startUkeyAuth(); void startAuth(qint32 uid, const DeviceInfoPtr deviceInfo); void stopAuth(); bool isAuthenticating(); void init(); /** * @brief 设置一些认证时所需的额外的信息 * @param info_type 额外的信息类型,ukey pincode认证时传 "pincode" * @param extra_info 额外的信息内容,ukey pincode认证时传PIN码内容 * @return 结果: (设置额外信息的结果) */ int SetExtraInfo(QString info_type, QString extra_info); /** * @brief 获取当前用户已连接设备对应特征数目 * @param uid 用户id * @param indexStart 用于认证的特征索引范围 * @param indexEnd * @return 返回是否存在ukey特征 */ bool GetHasUkeyFeature(int uid, int indexStart = 0, int indexEnd = -1); signals: void authComplete(int uid, bool result, int retErrNo); void authFinished(); void notify(const QString &message); void notifyDetail(int deviceId, const QString &message); void frameWritten(int deviceId); private slots: void onIdentityComplete(QDBusPendingCallWatcher *watcher); void onStatusChanged(int deviceId, int statusType); void onFrameWritten(int drvid); private: QDBusInterface *serviceInterface; qint32 uid; DeviceInfoPtr deviceInfo = nullptr; bool isInAuthentication; }; #endif // BIOAUTH_H ukui-biometric-auth/bioauth/include/biometric.h0000664000175000017500000000152315167732630020606 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef BIOMETRIC_H #define BIOMETRIC_H #include "bioauth.h" #include "biodevices.h" #include "bioauthwidget.h" #include "biodeviceswidget.h" #endif // BIOMETRIC_H ukui-biometric-auth/bioauth/include/bioauthwidget.h0000664000175000017500000000344515167732630021475 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef BIOAUTHWIDGET_H #define BIOAUTHWIDGET_H #include #include "bioauth.h" namespace Ui { class BioAuthWidget; } class BioAuthWidget : public QWidget { Q_OBJECT public: explicit BioAuthWidget(QWidget *parent = 0); ~BioAuthWidget(); void hidePasswdButton(); bool isAuthenticating(); public slots: void startAuth(uid_t uid, const DeviceInfoPtr device); void setMoreDevices(bool hasMore); void stopAuth(); void emitSwithToPassword(); signals: void switchToPassword(); void selectDevice(); void authComplete(uid_t uid, bool ret); private slots: void on_btnPasswdAuth_clicked(); void on_btnMore_clicked(); void on_btnRetry_clicked(); void onBioAuthNotify(const QString ¬ifyMsg); void onBioAuthComplete(uid_t uid, bool ret, int retErrNo); void onFrameWritten(int deviceId); private: void setMovie(); void setImage(); private: Ui::BioAuthWidget *ui; BioAuth *bioAuth; uid_t uid; DeviceInfoPtr device; int fd = -1; int dup_fd = -1; int nMaxFailCnt = 5; public: static int failedCount; }; #endif // BIOAUTHWIDGET_H ukui-biometric-auth/bioauth/include/uniauthservice.h0000664000175000017500000000531015167732644021672 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef UNIAUTH_SERVICE_H #define UNIAUTH_SERVICE_H // QtDBus 包含路径兼容 #if QT_VERSION_MAJOR == 6 #include #else #include #endif #include enum authEnableType { ENABLETYPE_BIO, // 全局总使能 ENABLETYPE_SAVER, // 锁屏 ENABLETYPE_GREETER, // 登录 ENABLETYPE_POLKIT, // 授权 ENABLETYPE_SU, // 暂保留 ENABLETYPE_SUDO, // 暂保留 ENABLETYPE_LOGIN, // 暂保留 }; class UniAuthService : public QDBusAbstractInterface { Q_OBJECT public: explicit UniAuthService(QObject *parent = nullptr); public Q_SLOTS: // 设置默认设备 void setDefaultDevice(int bioDevType, QString deviceName); // 获取默认设备 QString getDefaultDevice(QString userName, int bioDevType); // 获取所有默认设备 QStringList getAllDefaultDevice(QString userName); //生物特征开关接口 bool getBioAuthStatus(QString userName, int bioAuthType); void setBioAuthStatus(int bioAuthType, bool status); // 获取最大失败次数 int getMaxFailedTimes(); // 获取是否使能微信扫码登录 bool getQRCodeEnable(); // 获取是否双认证 bool getDoubleAuth(); // 获取用户绑定 bool getUserBind(); // 获取是否在控制面板显示 bool getIsShownInControlCenter(); // 获取是否使用第一个设备 bool getUseFirstDevice(); // 获取是否隐藏切换按钮 bool getHiddenSwitchButton(); // 获取正在认证的应用 QStringList getAuthingApp(); // 获取应用认证的驱动 int getAuthingAppDrivd(QString appName); public: bool isActivatable(); void recordAuthDrive(QString appName,int drvid,bool insert); Q_SIGNALS: //默认设备改变 void defaultDeviceChanged(QString userName, int bioDevType, QString deviceName); //开关状态改变 void bioAuthStatusChanged(QString userName, int type, bool status); private: bool m_isActivatable; }; #endif // UNIAUTH_SERVICE_H ukui-biometric-auth/bioauth/include/giodbus.h0000664000175000017500000000140515167732630020264 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef GIODBUS_H #define GIODBUS_H int get_server_gvariant_stdout(int drvid); #endif ukui-biometric-auth/bioauth/include/biodeviceswidget.h0000664000175000017500000000320515167732630022150 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef BIODEVICESWIDGET_H #define BIODEVICESWIDGET_H #include #include "biodevices.h" #define UKUI_BIOMETRIC_SYS_CONFIG_PATH "/etc/biometric-auth/ukui-biometric.conf" namespace Ui { class BioDevicesWidget; } class BioDevicesWidget : public QWidget { Q_OBJECT public: explicit BioDevicesWidget(QWidget *parent = 0); void setCurrentDevice(DeviceInfoPtr device); ~BioDevicesWidget(); void init(uid_t uid); enum FLAG{FIRST,AGAIN}; signals: void back(); void deviceChanged(const DeviceInfo &device); void deviceCountChanged(int count); private slots: // void on_btnBack_clicked(); // void on_btnOK_clicked(); void on_lwDevices_currentIndexChanged(); void on_cmbDeviceTypes_currentIndexChanged(int index); void onDeviceCountChanged(); private: Ui::BioDevicesWidget *ui; BioDevices bioDevices; QMap> devicesMap; uid_t uid; }; int GetFailedTimes(); #endif // BIODEVICESWIDGET_H ukui-biometric-auth/bioauth/include/biodevices.h0000664000175000017500000000651515167732644020760 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef BIODEVICES_H #define BIODEVICES_H #include #include #include #include "biotypes.h" #include "uniauthservice.h" class QDBusInterface; #define SHARE_BIOMETRIC_CONFIG_PATH \ "/var/lib/lightdm-data/%1/ukui-biometric.conf" // greeter、screensaver、polkit share conf /*! * \brief The BioDevices class * this class saves the list of all device information * and list of available devices' info list for each uid */ class BioDevices : public QObject { Q_OBJECT public: explicit BioDevices(bool isIgnoreQrCode = false, QObject *parent = nullptr); int count(); void setUId(int nUId); QMap> getAllDevices(); QMap> getUserDevices(int uid); QList getDevices(int type); DeviceInfoPtr getDefaultDevice(uid_t uid); DeviceInfoPtr getDefaultDevice(uid_t uid, int bioType); int GetLastDevice(const QString &userName); void SetLastDevice(const QString &userName, int drvid); DeviceInfoPtr findDevice(const QString &deviceName); DeviceInfoPtr findDevice(const int id); DeviceList findDeviceByType(int nBioType); DeviceInfoPtr getFirstDevice(int uid); DeviceList GetDevList(); int getFeatureCount(int uid, int indexStart = 0, int indexEnd = -1); static QString bioTypeToString_tr(int type); void setIsShowHotPlug(bool isShow); int GetUserDevFeatureCount(int uid, int drvid); int GetUserDevCount(int uid); FeatureMap GetUserFeatures(int uid); bool getUseFirstDevice(); int getFailedTimes(); bool GetHiddenSwitchButton(); bool GetQRCodeEnable(); bool GetBioAuthEnable(); QStringList getAllDefDevices(); /** * @brief UpdateStatus 获取更新的设备状态 * @param drvid 驱动id * @return 结果: */ StatusReslut UpdateStatus(int drvid); bool GetBioAuthEnable(uid_t uid); bool GetDirveIsIdle(int drvid); void recordAuthDrive(QString appName, int drvid, bool insert); private: void connectToService(); void getDevicesList(); signals: void deviceCountChanged(int newNum); private slots: void onUSBDeviceHotPlug(int deviceId, int action, int devNumNow); private: QDBusInterface *serviceInterface; DeviceList deviceInfos; // the list of al device info bool isShowHotPlug; bool useFirstDevice; bool m_isIgnoreQrCode = false; UniAuthService *m_uniAuthService = nullptr; int m_nUId = -1; QList m_listPriority; }; #endif // BIODEVICES_H ukui-biometric-auth/bioauth/include/biotypes.h0000664000175000017500000001754115167732644020503 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef BIOCUSTOMTYPE_H #define BIOCUSTOMTYPE_H #include // QtDBus 包含路径兼容 #if QT_VERSION_MAJOR == 6 #include #else #include #endif #define BIO_DBUS_SERVICE "org.ukui.Biometric" #define BIO_DBUS_PATH "/org/ukui/Biometric" #define BIO_DBUS_INTERFACE "org.ukui.Biometric" #define DEFAULT_DEVICE "DefaultDevice" #ifdef LOG #undef LOG #endif #define LOG() qDebug() << "[BIOMETRIC]" enum LOGINOPT_TYPE { LOGINOPT_TYPE_PASSWORD = 0, // 密码 LOGINOPT_TYPE_FACE, // 人脸 LOGINOPT_TYPE_FINGERPRINT, // 指纹 LOGINOPT_TYPE_IRIS, // 虹膜 LOGINOPT_TYPE_VOICEPRINT, // 声纹 LOGINOPT_TYPE_FINGERVEIN, // 指静脉 LOGINOPT_TYPE_GENERAL_UKEY, // 普通的ukey LOGINOPT_TYPE_ADVANCED_UKEY, // 高阶的ukey LOGINOPT_TYPE_QRCODE, // 二维码 LOGINOPT_TYPE_OTHERS, // 其他 LOGINOPT_TYPE_COUNT }; /* the type of device */ enum BioType { BIOTYPE_FINGERPRINT, BIOTYPE_FINGERVEIN, BIOTYPE_IRIS, BIOTYPE_FACE, BIOTYPE_VOICEPRINT, __MAX_NR_BIOTYPES }; #define REMOTE_QRCODE_TYPE (8) /* StatusChanged D-Bus 信号触发时的状态变化类型 */ enum StatusType { STATUS_DEVICE, STATUS_OPERATION, STATUS_NOTIFY }; /* 录入/删除/搜索等 D-Bus 调用的最终结果,即返回值里的 result */ enum DBusResult { DBUS_RESULT_SUCCESS = 0, DBUS_RESULT_ERROR, DBUS_RESULT_DEVICEBUSY, DBUS_RESULT_NOSUCHDEVICE, DBUS_RESULT_PERMISSIONDENIED }; /** * @brief 识别操作(Identify)的ops状态 */ /* 定义操作类型 */ typedef enum { OPS_TYPE_COMM = 0, OPS_TYPE_OPEN, OPS_TYPE_ENROLL, OPS_TYPE_VERIFY, OPS_TYPE_IDENTIFY, OPS_TYPE_CAPTURE, OPS_TYPE_SEARCH, OPS_TYPE_CLEAN, OPS_TYPE_GET_FLIST, OPS_TYPE_RENAME, OPS_TYPE_CLOSE, }BioOpsType; /* * 定义各种操作结果 */ typedef enum { OPS_COMM_SUCCESS = OPS_TYPE_COMM * 100, /** 空闲状态 **/ OPS_COMM_FAIL, /** 操作失败 **/ OPS_COMM_NO_MATCH = OPS_COMM_FAIL, /** 不匹配 **/ OPS_COMM_ERROR, /** 通用操作错误 **/ OPS_COMM_STOP_BY_USER, /** 用户取消 **/ OPS_COMM_TIMEOUT, /** 操作超时 **/ OPS_COMM_OUT_OF_MEM, /** 无法分配内存 **/ OPS_COMM_MAX, OPS_OPEN_SUCCESS = OPS_TYPE_OPEN * 100, /** 打开设备完成 **/ OPS_OPEN_FAIL, /** 打开设备失败 **/ OPS_OPEN_ERROR, /** 打开设备遇到错误 **/ OPS_OPEN_MAX, OPS_ENROLL_SUCCESS = OPS_TYPE_ENROLL * 100, /** 录入信息成功 **/ OPS_ENROLL_FAIL, /** 录入失败 **/ OPS_ENROLL_ERROR, /** 录入过程中遇到错误 **/ OPS_ENROLL_STOP_BY_USER, /** 录入被用户中断 **/ OPS_ENROLL_TIMEOUT, /** 操作超时 **/ OPS_ENROLL_MAX, OPS_VERIFY_MATCH = OPS_TYPE_VERIFY * 100, /** 认证匹配 **/ OPS_VERIFY_NO_MATCH, /** 认证不匹配 **/ OPS_VERIFY_ERROR, /** 认证过程中遇到错误 **/ OPS_VERIFY_STOP_BY_USER, /** 认证被用户中断 **/ OPS_VERIFY_TIMEOUT, /** 操作超时 **/ OPS_VERIFY_MAX, OPS_IDENTIFY_MATCH = OPS_TYPE_IDENTIFY * 100, /** 识别到指定特征 **/ OPS_IDENTIFY_NO_MATCH, /** 未识别出指定特征 **/ OPS_IDENTIFY_ERROR, /** 识别过程中遇到错误 **/ OPS_IDENTIFY_STOP_BY_USER, /** 识别被用户中断 **/ OPS_IDENTIFY_TIMEOUT, /** 操作超时 **/ OPS_IDENTIFY_MAX, OPS_CAPTURE_SUCCESS = OPS_TYPE_CAPTURE * 100, /** 捕获成功 **/ OPS_CAPTURE_FAIL, /** 捕获失败 **/ OPS_CAPTURE_ERROR, /** 捕获过程中遇到错误 **/ OPS_CAPTURE_STOP_BY_USER, /** 捕获被用户中断 **/ OPS_CAPTURE_TIMEOUT, /** 操作超时 **/ OPS_CAPTURE_MAX, OPS_SEARCH_MATCH = OPS_TYPE_SEARCH * 100, /** 搜索到指定特征 **/ OPS_SEARCH_NO_MATCH, /** 未搜索到指定特征 **/ OPS_SEARCH_ERROR, /** 搜索过程中遇到错误 **/ OPS_SEARCH_STOP_BY_USER, /** 搜索被用户中断 **/ OPS_SEARCH_TIMEOUT, /** 操作超时 **/ OPS_SEARCH_MAX, OPS_CLEAN_SUCCESS = OPS_TYPE_CLEAN * 100, /** 清理特征成功 **/ OPS_CLEAN_FAIL, /** 清理失败 **/ OPS_CLEAN_ERROR, /** 清理过程中遇到错误 **/ OPS_CLEAN_STOP_BY_USER, /** 清理被用户中断 **/ OPS_CLEAN_TIMEOUT, /** 操作超时 **/ OPS_CLEAN_MAX, OPS_GET_FLIST_SUCCESS = OPS_TYPE_GET_FLIST * 100, /** 获取特征列表完成 **/ OPS_GET_FLIST_FAIL, /** 获取特征列表失败 **/ OPS_GET_FLIST_ERROR, /** 获取特征列表过程中遇到错误 **/ OPS_GET_FLIST_STOP_BY_USER, /** 获取特征列表被用户中断 **/ OPS_GET_FLIST_TIMEOUT, /** 获取特征列表超时 **/ OPS_GET_FLIST_MAX, OPS_RENAME_SUCCESS = OPS_TYPE_RENAME * 100, /** 重命名特征完成 **/ OPS_RENAME_FAIL, /** 重命名特征失败 **/ OPS_RENAME_ERROR, /** 重命名特征过程中遇到错误 **/ OPS_RENAME_STOP_BY_USER, /** 重命名特征被用户中断 **/ OPS_RENAME_TIMEOUT, /** 重命名特征超时 **/ OPS_RENAME_MAX, OPS_CLOSE_SUCCESS = OPS_TYPE_CLOSE * 100, /** 关闭设备完成 **/ OPS_CLOSE_FAIL, /** 关闭设备失败 **/ OPS_CLOSE_ERROR, /** 关闭设备过程中遇到错误 **/ OPS_CLOSE_MAX, }OpsResult; /** * @brief UpdateStauts调用返回的结果 */ struct StatusReslut { int result; int enable; int devNum; int devStatus; int opsStatus; int notifyMessageId; }; struct FeatureInfo { int uid; int biotype; QString device_shortname; int index; QString index_name; }; /* the info of device */ struct DeviceInfo { int device_id; QString device_shortname; /* aka driverName */ QString device_fullname; int driver_enable; /* The corresponding driver is enabled/disabled */ int device_available; /* The driver is enabled and the device is connected */ int biotype; int stotype; int eigtype; int vertype; int idtype; int bustype; int dev_status; int ops_status; bool operator==(const DeviceInfo&) const; bool operator !=(const DeviceInfo &deviceInfo) const { return !(*this == deviceInfo); } friend QDebug& operator<<(QDebug &stream, const DeviceInfo &deviceInfo); }; Q_DECLARE_METATYPE(DeviceInfo) typedef std::shared_ptr DeviceInfoPtr; typedef QList DeviceList; typedef QMap DeviceMap; typedef std::shared_ptr FeatureInfoPtr; typedef QList FeatureList; typedef QMap FeatureMap; QDBusArgument &operator<<(QDBusArgument &argument, const DeviceInfo &deviceInfo); const QDBusArgument &operator>>(const QDBusArgument &argument, DeviceInfo &deviceInfo); QDebug operator <<(QDebug stream, const DeviceInfo &deviceInfo); QDBusArgument &operator<<(QDBusArgument &argument, const FeatureInfo &featureInfo); const QDBusArgument &operator>>(const QDBusArgument &argument, FeatureInfo &featureInfo); QString bioTypeToString(int type); #endif // BIOCUSTOMTYPE_H ukui-biometric-auth/common/0000775000175000017500000000000015167732644014676 5ustar fengfengukui-biometric-auth/common/qt_matrix_compat.h0000664000175000017500000000506415167732644020427 0ustar fengfeng/* * Copyright (C) 2025 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef QT_MATRIX_COMPAT_H #define QT_MATRIX_COMPAT_H #include #include #if QT_VERSION_MAJOR == 6 // Qt6中使用QTransform替代QMatrix typedef QTransform QMatrix; // 为了保持API兼容性,提供一些QMatrix特有的方法 namespace QtMatrixCompat { // QMatrix的rotate方法在QTransform中对应rotate inline void rotateMatrix(QTransform& matrix, qreal angle) { matrix.rotate(angle); } // QMatrix的scale方法在QTransform中对应scale inline void scaleMatrix(QTransform& matrix, qreal sx, qreal sy) { matrix.scale(sx, sy); } // QMatrix的translate方法在QTransform中对应translate inline void translateMatrix(QTransform& matrix, qreal dx, qreal dy) { matrix.translate(dx, dy); } } #else // Qt5中直接使用QMatrix #include // 为了保持一致性,提供相同的命名空间 namespace QtMatrixCompat { inline void rotateMatrix(QMatrix& matrix, qreal angle) { matrix.rotate(angle); } inline void scaleMatrix(QMatrix& matrix, qreal sx, qreal sy) { matrix.scale(sx, sy); } inline void translateMatrix(QMatrix& matrix, qreal dx, qreal dy) { matrix.translate(dx, dy); } } #endif // 提供QPixmap::transformed的兼容性处理 namespace QtPixmapCompat { inline QPixmap transformedPixmap(const QPixmap& pixmap, const QMatrix& matrix, Qt::TransformationMode mode = Qt::FastTransformation) { #if QT_VERSION_MAJOR == 6 // 在Qt6中,QMatrix实际上是QTransform return pixmap.transformed(static_cast(matrix), mode); #else // 在Qt5中,直接使用QMatrix return pixmap.transformed(matrix, mode); #endif } } #endif // QT_MATRIX_COMPAT_H ukui-biometric-auth/common/qt_desktop_compat.h0000664000175000017500000000733415167732644020576 0ustar fengfeng/* * Copyright (C) 2025 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef QT_DESKTOP_COMPAT_H #define QT_DESKTOP_COMPAT_H #include #include // QDesktopWidget 兼容性处理 #if QT_VERSION_MAJOR == 6 #include // Qt6中QDesktopWidget已被移除,使用QScreen替代 inline QScreen* getDesktopWidget() { return QApplication::primaryScreen(); } inline QRect getDesktopGeometry() { QScreen* screen = QApplication::primaryScreen(); return screen ? screen->geometry() : QRect(); } inline int getScreenCount() { return QApplication::screens().count(); } // 连接屏幕变化信号的兼容性函数 template void connectScreenSignals(Receiver* receiver, Slot slot) { QApplication* app = qApp; QObject::connect(app, &QApplication::primaryScreenChanged, receiver, slot); QObject::connect(app, &QApplication::screenAdded, receiver, slot); QObject::connect(app, &QApplication::screenRemoved, receiver, slot); } template void disconnectScreenSignals(Receiver* receiver, Slot slot) { QApplication* app = qApp; QObject::disconnect(app, &QApplication::primaryScreenChanged, receiver, slot); QObject::disconnect(app, &QApplication::screenAdded, receiver, slot); QObject::disconnect(app, &QApplication::screenRemoved, receiver, slot); } #else #include inline QDesktopWidget* getDesktopWidget() { return QApplication::desktop(); } inline QRect getDesktopGeometry() { QDesktopWidget* desktop = QApplication::desktop(); return desktop ? desktop->geometry() : QRect(); } inline int getScreenCount() { QDesktopWidget* desktop = QApplication::desktop(); return desktop ? desktop->screenCount() : 0; } // 连接屏幕变化信号的兼容性函数 template void connectScreenSignals(Receiver* receiver, Slot slot) { QDesktopWidget* desktop = QApplication::desktop(); if (desktop) { QObject::connect(desktop, SIGNAL(resized(int)), receiver, slot); QObject::connect(desktop, SIGNAL(workAreaResized(int)), receiver, slot); QObject::connect(desktop, SIGNAL(primaryScreenChanged(QScreen*)), receiver, slot); QObject::connect(desktop, SIGNAL(screenCountChanged(int)), receiver, slot); } } template void disconnectScreenSignals(Receiver* receiver, Slot slot) { QDesktopWidget* desktop = QApplication::desktop(); if (desktop) { QObject::disconnect(desktop, SIGNAL(resized(int)), receiver, slot); QObject::disconnect(desktop, SIGNAL(workAreaResized(int)), receiver, slot); QObject::disconnect(desktop, SIGNAL(primaryScreenChanged(QScreen*)), receiver, slot); QObject::disconnect(desktop, SIGNAL(screenCountChanged(int)), receiver, slot); } } #endif #endif // QT_DESKTOP_COMPAT_H ukui-biometric-auth/common/generic.h0000664000175000017500000000301115167732630016451 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #ifndef GENERIC_H #define GENERIC_H #define BIO_ERROR -1 #define BIO_FAILED 0 #define BIO_SUCCESS 1 #define BIO_IGNORE 2 #define BIOMETRIC_PAM_DOUBLE "BIOMETRIC_PAM_DOUBLE" #define BIOMETRIC_PAM "BIOMETRIC_PAM" #define BIOMETRIC_PAM_QRCODE "BIOMETRIC_PAM_QRCODE" #define BIOMETRIC_IGNORE "BIOMETRIC_IGNORE" #define BIOMETRIC_SUCCESS "BIOMETRIC_SUCCESS" #define BIOMETRIC_FAILED "BIOMETRIC_FAILED" #define BIO_COM_FILE "/tmp/bio_com" #define STR(s) #s #define GET_STR(s) STR(s) #define _MULTI_THREADED #define AGENT_NAME "polkit-ukui-authentication-agent" #define POLKIT_LISTENER_ID "/org/ukui/PolicyKit1/AuthenticationAgent" #ifdef __cplusplus #include "qlogging.h" extern bool enableDebug; extern QString logPrefix; void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg); #endif #endif ukui-biometric-auth/common/generic.cpp0000664000175000017500000000377115167732630017021 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include "generic.h" #include #include void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &msg) { Q_UNUSED(context) if(!enableDebug) return; QDateTime dateTime = QDateTime::currentDateTime(); QByteArray time = QString("[%1] ").arg(dateTime.toString("MM-dd hh:mm:ss.zzz")).toLocal8Bit(); QByteArray localMsg = msg.toLocal8Bit(); QByteArray prefix = logPrefix.toLocal8Bit(); switch(type) { case QtDebugMsg: fprintf(stderr, "%s %s [Debug]: %s\n", prefix.constData(), time.constData(), localMsg.constData()); break; #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) case QtInfoMsg: fprintf(stderr, "%s %s [Info]: %s\n", prefix.constData(), time.constData(), localMsg.constData()); break; #endif case QtWarningMsg: fprintf(stderr, "%s %s [Warnning]: %s\n", prefix.constData(), time.constData(), localMsg.constData()); break; case QtCriticalMsg: fprintf(stderr, "%s %s [Critical]: %s\n", prefix.constData(), time.constData(), localMsg.constData()); break; case QtFatalMsg: fprintf(stderr, "%s %s [Fatal]: %s\n", prefix.constData(), time.constData(), localMsg.constData()); abort(); } } ukui-biometric-auth/pam-biometric/0000775000175000017500000000000015167732644016136 5ustar fengfengukui-biometric-auth/pam-biometric/biotest.c0000664000175000017500000001001115167732644017744 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include #define BUF_SIZE 128 #define DISABLE_ECHO 0 #define ENABLE_ECHO 1 char * getpasswd(int enable_echo); int pam_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr); struct pam_conv conv = { pam_conversation, NULL }; int pam_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) { int count = num_msg; char *password = 0; *resp = (struct pam_response *)malloc(num_msg * sizeof(struct pam_response)); /*指针备份,下面的循环需要指针后移*/ struct pam_response *tmp_save = (struct pam_response *)(*resp); memset(*resp, 0, num_msg * sizeof(struct pam_response)); while(count-- >= 1){ switch((*msg)->msg_style){ case PAM_PROMPT_ECHO_OFF: printf("%s",(*msg)->msg); password = getpasswd(DISABLE_ECHO); (*resp)->resp = password; (*resp)->resp_retcode = 0; break; case PAM_PROMPT_ECHO_ON: printf("%s",(*msg)->msg); password = getpasswd(ENABLE_ECHO); (*resp)->resp = password; (*resp)->resp_retcode = 0; break; case PAM_ERROR_MSG: printf("%s",(*msg)->msg); break; case PAM_TEXT_INFO: printf("%s",(*msg)->msg); break; default: printf("Should not reach here!\n"); } if(count != 0){ msg++; (*resp)++; } } /*指针归位 方法1*/ /* unsigned long address_value = (unsigned long)(*resp) - (num_msg -1) * sizeof(struct pam_response); (*resp) = (struct pam_response *)address_value; */ /*指针归位 方法2*/ (*resp) = tmp_save; return PAM_SUCCESS; } int main(int argc, char *argv[]) { pam_handle_t *pamh = NULL; int retval; char *user = NULL; if(argc == 2){ user = argv[1]; } else { printf("Usage: You must specify a username.\n"); exit(1); } retval = pam_start("biotest", user, &conv, &pamh); if(retval == PAM_SUCCESS){ printf("PAM started Success.\n"); } else { printf("PAM started Failed.\n"); } int auth_status = pam_authenticate(pamh,0); if(auth_status != PAM_SUCCESS){ const char * error_msg = pam_strerror(pamh, auth_status); printf("Auth Status : %s\n",error_msg); } else { printf("Authenticate Success!\n"); auth_status = pam_acct_mgmt(pamh, 0); } if(pam_end(pamh, retval) != PAM_SUCCESS){ pamh = NULL; printf("Failed to terminate PAM."); exit(1); } return (retval == PAM_SUCCESS ? 0:1); } char * getpasswd(int enable_echo) { struct termios tp, save; char *password = (char *)malloc(BUF_SIZE * sizeof(char)); /* printf("Input Password:"); fflush(stdout); */ if (tcgetattr(STDIN_FILENO, &tp) == -1){ printf("tcgetattr error\n"); exit(1); } save = tp;/* So we can restore settings later */ if(enable_echo) ;/*Default is echo. Do nothing*/ else tp.c_lflag &= ~ECHO;/* ECHO off, other bits unchanged */ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &tp) == -1){ printf("tcgetattr error\n"); exit(1); } /* Read some input */ if (fgets(password, BUF_SIZE, stdin) == NULL) printf("Got end-of-file/error on fgets()\n"); else ; /* Restore original terminal settings */ if (tcsetattr(STDIN_FILENO, TCSANOW, &save) == -1){ printf("tcgetattr error\n"); exit(1); } /*fgets读入的字符串末尾有回车符,在此替换为\0*/ password[strnlen(password,128)-1] = '\0'; return password; } ukui-biometric-auth/pam-biometric/pam_biometric.c0000664000175000017500000005370115167732644021122 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #define PAM_SM_AUTH #include "generic.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USER_CONFIG_FILE "/home/%s/.biometric_auth/ukui_biometric.conf" /* Declare log function */ extern int pam_enable_debug; extern char *pam_log_prefix; extern int pam_logger(char *format, ...); static int ukui_biometric_lock = 0; int enable_biometric_authentication(pam_handle_t *pamh); int enable_qrcode_authentication(pam_handle_t *pamh); int enable_biometric_auth_double(); /* GUI child process alive status */ static int child_alive = 1; /* Signal handler */ static void signal_handler(int signo) { if (signo == SIGUSR1) child_alive = 0; /* GUI child process has terminated */ pam_logger("signal_handler is triggered\n"); } int enable_biometric_authentication_app() { char conf_file[] = GET_STR(CONFIG_FILE); FILE *file; char line[1024]; int i; int is_enable = 0; if((file = fopen(conf_file, "r")) == NULL){ pam_logger("open configure file failed: %s\n", strerror(errno)); return 1; } while(fgets(line, sizeof(line), file)) { i = sscanf(line, "EnableAuthApp=%d\n", &is_enable); if(i > 0) { pam_logger("EnableAuthApp=%d\n", is_enable); break; } } fclose(file); return is_enable; } /* * Check if the service should use biometric authentication */ int service_filter(char *service) { //int is_enable = enable_biometric_authentication_app(); //syslog(LOG_INFO,"is_enable = %d service = %s\n",is_enable,service); if (strcmp(service, "lightdm") == 0) { //if(is_enable & 1 == 0) // return 0; return 1; } if (strcmp(service, "ukui-screensaver-qt") == 0){ //if((is_enable & (1<<1)) == 0) // return 0; return 1; } if (strcmp(service, "polkit-1") == 0){ //if((is_enable & (1<<2)) == 0) // return 0; return 1; } if (strcmp(service, "sudo") == 0){ //if((is_enable & (1<<3)) == 0) // return 0; return 1; } if (strcmp(service, "su") == 0){ //if((is_enable & (1<<4)) == 0) // return 0; return 1; } if (strcmp(service, "login") == 0){ //if((is_enable & (1<<5)) == 0) // return 0; return 1; } #ifdef ENABLE_BIOTEST if (strcmp(service, "biotest") == 0) return 1; #endif return 0; } /* * Invoke the PAM conversation function */ int call_conversation(pam_handle_t *pamh, int msg_style, char *msg, char *resp, int resp_length) { /* PAM data structures used by conversation */ const struct pam_message *message[1] = {0}; struct pam_message *message_tmp = 0; struct pam_response *response = 0; const struct pam_conv *conv_struct = 0; int status = -1; status = pam_get_item(pamh, PAM_CONV, (const void **)&conv_struct); if (status != PAM_SUCCESS) return PAM_SYSTEM_ERR; message_tmp = (struct pam_message *)malloc(sizeof(struct pam_message)); message_tmp->msg_style = msg_style; message_tmp->msg = msg; message[0] = message_tmp; pam_logger("Call conv callback function\n"); status = conv_struct->conv(1, message, &response, conv_struct->appdata_ptr); pam_logger("Finish conv callback function\n"); if (resp && response->resp && resp_length > 1) snprintf(resp, resp_length - 1, "%s", response->resp); /* Use typecast to suppress gcc warnings */ free((void *)message[0]); if (response->resp) free(response->resp); free(response); return status; } /* GUI child process */ void child(char *service, char *username, char *xdisp) { pam_logger("Child process will be replaced.\n"); int fd = open("/dev/null", O_WRONLY); dup2(fd, 2); execl("/usr/bin/bioauth", "bioauth", "--service", service, "--user", username, // "--display", xdisp, pam_enable_debug ? "--debug" : "", (char *)0); /* * execl almost always succeed as long as the GUI executable file exists. * Though invoking GUI under console will exit with error, the GUI child * process won't reach here. Therefore, the following code won't be * executed in general. */ pam_logger("Fatal error: execl(gui) failed in child process. " "This is an extremely rare condition. Please ensure that the " "biometric-authentication executable file exists.\n"); pam_logger("Use password as a fallback\n"); pam_logger("Child _exit with BIO_IGNORE\n"); /* Child process exits */ _exit(BIO_IGNORE); } void handler(int signo) { (void)signo; // 避免未使用参数警告 return; } /* PAM parent process */ int parent(int pid, pam_handle_t *pamh, int need_call_conv) { pam_logger("Parent process continue running.\n"); int child_status = -1; /* * 1. If calling conversation function is not needed, wait the child * until it exits. * 2. Otherwise, send a text info to application at first and then * call the conversation function to request the password. The returned * password is unused. * Note: During requesting the password, screensaver won't display the * prompting message, while greeter will display it into the password * entry. If there is a "\n" at the end of the message, it will be * displayed on the Label above the password entry. */ if (need_call_conv) { char *lang = getenv("LANG"); char *msg1, *msg2; if (lang && !strncmp(lang, "zh_CN", 5)) msg1 = "请进行生物识别或点击“切换到密码登录”\n"; else msg1 = "Use biometric authentication or click " "\"Switch to password\"\n"; #ifdef EMPTY_PAM_PWD_PROMPT msg2 = ""; #else msg2 = "pam_biometric.so needs a fake ENTER:"; #endif if (signal(SIGUSR1, signal_handler) == SIG_ERR) pam_logger("Fatal Error. Can't catch SIGUSR1\n"); reinvoke: call_conversation(pamh, PAM_TEXT_INFO, msg1, NULL, 0); call_conversation(pamh, PAM_PROMPT_ECHO_OFF, msg2, NULL, 0); /* GUI child process is still alive. This enter is typed by user. */ if (child_alive == 1) goto reinvoke; signal(SIGUSR1, SIG_DFL); waitpid(pid, &child_status, 0); } else { pam_logger("Waiting for the GUI child process to exit...\n"); //由于sudo命令在进入pam认证时,会阻塞来自终端的SIGINT以及SIGQUIT信号,导致使用 //pam认证时,按下Ctrl+C无反应,认证完成后,sudo会退出,这里为了简单,取消了阻塞 //信号,捕获信号但不做处理,在认证完成后,恢复原本阻塞状态 sigset_t mask; sigprocmask(SIG_BLOCK,NULL,&mask); sigprocmask(SIG_UNBLOCK,&mask,NULL); signal(SIGINT,handler); waitpid(pid, &child_status, 0); pam_logger("GUI child process has exited.\n"); sigprocmask(SIG_SETMASK,&mask,NULL); } /* * Determine the return value of PAM according to the return value of * child process. */ int bio_result = BIO_ERROR; /* biometric result code */ if (WIFEXITED(child_status)) bio_result = WEXITSTATUS(child_status); else /* This may be because the GUI child process is invoked under console. */ pam_logger("The GUI-Child process terminate abnormally.\n"); if (bio_result == BIO_SUCCESS) { if(!enable_biometric_authentication(pamh) && !enable_qrcode_authentication(pamh)) { pam_logger("disable biometric authentication.\n"); return PAM_SYSTEM_ERR; } pam_logger("pam_biometric.so return PAM_SUCCESS\n"); return PAM_SUCCESS; } else if (bio_result == BIO_IGNORE) { /* Override msg1 to empty the label. We are ready to enter the password module. */ call_conversation(pamh, PAM_TEXT_INFO, "", NULL, 0); ukui_biometric_lock = 1; pam_logger("pam_biometric.so return PAM_IGNORE\n"); return PAM_IGNORE; } else { pam_logger("pam_biometric.so return PAM_SYSTEM_ERR\n"); ukui_biometric_lock = 1; return PAM_SYSTEM_ERR; } } /* Set environment variables related to displaying */ void check_and_set_env(pam_handle_t *pamh, char **xdisp, char **xauth) { *xdisp=getenv("DISPLAY"); *xauth=getenv("XAUTHORITY"); if (*xdisp == 0){ pam_get_item(pamh, PAM_XDISPLAY, (const void **)xdisp); if (*xdisp) setenv("DISPLAY",*xdisp,-1); } if (*xauth == 0) setenv("XAUTHORITY", "/var/run/lightdm/root/:0", -1); *xdisp=getenv("DISPLAY"); *xauth=getenv("XAUTHORITY"); if (*xdisp == 0) pam_logger("Warning: DISPLAY env is still empty, " "this is not an error if you are using terminal\n"); if (*xauth == 0) pam_logger("Warning: XAUTHORITY env is still empty, " "this is not an error if you are using terminal\n"); } /* Biometric processing function for generic purpose */ int biometric_auth_independent(pam_handle_t *pamh , char *service, int need_call_conv) { /* Get the username */ char *username = 0; pam_get_item(pamh, PAM_USER, (const void **)&username); /* Check and set environment variables */ char *xdisp, *xauth; check_and_set_env(pamh, &xdisp, &xauth); /* Detach child process */ unsigned int pid; pid = fork(); if (pid < 0) { pam_logger("Fork Error!\n"); return PAM_SYSTEM_ERR; } else if (pid != 0) { return parent(pid, pamh, need_call_conv); } else { child(service, username, xdisp); pam_logger("Should never reach here.\n"); return PAM_SYSTEM_ERR; } } int biometric_auth_embeded(pam_handle_t *pamh) { /* * By convention, PAM module sends a string "BIOMETRIC_PAM" to * lightdm and this message will be forwarded to greeter. After * the authentication is completed, greeter will send a string * "BIOMETRIC_IGNORE"/"BIOMETRIC_SUCCESS" to lightdm and then it * will be forwarded to PAM module. We can get the authentication * status by comparing strings. */ char resp[96] = {0}; if(enable_biometric_auth_double()) call_conversation(pamh, PAM_PROMPT_ECHO_OFF, BIOMETRIC_PAM_DOUBLE, resp, sizeof(resp)); else call_conversation(pamh, PAM_PROMPT_ECHO_OFF, BIOMETRIC_PAM, resp, sizeof(resp)); if (strcmp(resp, BIOMETRIC_IGNORE) == 0) return PAM_IGNORE; else if (strcmp(resp, BIOMETRIC_SUCCESS) == 0){ if(!enable_biometric_authentication(pamh) && !enable_qrcode_authentication(pamh)) { pam_logger("disable biometric authentication.\n"); return PAM_SYSTEM_ERR; } return PAM_SUCCESS; } else if (strcmp(resp, BIOMETRIC_FAILED) == 0) return PAM_AUTH_ERR; else return PAM_SYSTEM_ERR; } void get_greeter_session(char buf[], int len) { GPtrArray *args_ps = NULL; gchar *stdout_ps = NULL; gchar *greeter_name = NULL; args_ps = g_ptr_array_new (); g_ptr_array_add(args_ps, (gpointer)"/usr/bin/ps"); g_ptr_array_add(args_ps, (gpointer)"-aux"); g_ptr_array_add(args_ps, (gpointer)"--columns"); g_ptr_array_add(args_ps, (gpointer)"256"); g_ptr_array_add(args_ps, NULL); if (!g_spawn_sync(NULL, (char**)args_ps->pdata, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &stdout_ps, NULL, NULL, NULL)) { if (stdout_ps) g_free(stdout_ps); g_ptr_array_free (args_ps, TRUE); return ; } if (stdout_ps) { gchar **lines = NULL; lines = g_strsplit(stdout_ps, "\n", 0); for (int n = 0; lines[n] != NULL; n++) { if (lines[n][0] == '\0') continue; gchar *res = g_strstr_len(lines[n], 1024, "greeter-session"); if (res) { gchar **greeter_args = g_strsplit(res, " ", 0); int arg_index = 0; for (int m = 0; greeter_args[m] != NULL; m++) { if (greeter_args[m][0] == '\0') continue; // greeter-session arg1 if (arg_index == 1) { gchar *greeter = g_strrstr_len(greeter_args[m], 256, "/"); if (greeter && strnlen(greeter,1024) > 1) { greeter_name = g_strdup(greeter + 1); break; } } arg_index ++; } g_strfreev(greeter_args); if (greeter_name) { break; } } } g_strfreev(lines); g_free(stdout_ps); } g_ptr_array_free (args_ps, TRUE); if (greeter_name) { g_strlcpy(buf, greeter_name, len); g_free(greeter_name); } else { GPtrArray *args_pidof = NULL; gchar *stdout_pidof = NULL; args_pidof = g_ptr_array_new (); g_ptr_array_add(args_pidof, (gpointer)"/usr/bin/pidof"); g_ptr_array_add(args_pidof, (gpointer)"ukui-greeter"); g_ptr_array_add(args_pidof, NULL); if (!g_spawn_sync(NULL, (char**)args_pidof->pdata, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &stdout_pidof, NULL, NULL, NULL)) { if (stdout_pidof) g_free(stdout_pidof); g_ptr_array_free (args_pidof, TRUE); //如果ukui-greeter进程不存在,进而判断ukui-screensaver-backend进程 args_pidof = g_ptr_array_new (); g_ptr_array_add(args_pidof, (gpointer)"/usr/bin/pidof"); g_ptr_array_add(args_pidof, (gpointer)"ukui-screensaver-backend"); g_ptr_array_add(args_pidof, NULL); if (!g_spawn_sync(NULL, (char**)args_pidof->pdata, NULL, G_SPAWN_STDERR_TO_DEV_NULL, NULL, NULL, &stdout_pidof, NULL, NULL, NULL)) { if (stdout_pidof) { g_free(stdout_pidof); stdout_pidof = NULL; } g_ptr_array_free (args_pidof, TRUE); } if (stdout_pidof) { if (strnlen(stdout_pidof,1024) > 0 && atoi(stdout_pidof) > 0) { g_strlcpy(buf, "ukui-screensaver-backend", len); } g_free(stdout_pidof); } g_ptr_array_free (args_pidof, TRUE); return ; } if (stdout_pidof) { if (strnlen(stdout_pidof,1024) > 0 && atoi(stdout_pidof) > 0) { g_strlcpy(buf, "ukui-greeter", len); } g_free(stdout_pidof); } g_ptr_array_free (args_pidof, TRUE); } } int enable_by_polkit() { FILE *file; char buf[1024]; if( (file = fopen(BIO_COM_FILE, "r")) == NULL) { pam_logger("open communication file failed: %s\n", strerror(errno)); return 0; } memset(buf, 0, sizeof(buf)); fgets(buf, sizeof(buf), file); fclose(file); if(remove(BIO_COM_FILE) < 0) pam_logger("remove communication file failed: %s\n", strerror(errno)); pam_logger("%s\n", buf); if(strcmp(buf, "polkit-ukui-authentication-agent-1") == 0) return 1; return 0; } int enable_biometric_authentication(pam_handle_t *pamh) { char *username = NULL; int is_found = 0; int is_auth_enable = 0; pam_get_item(pamh, PAM_USER, (const void **)&username); if (username) { char conf_file_user[256]; snprintf(conf_file_user, 255, USER_CONFIG_FILE, username); FILE *file = NULL; char line[1024], is_enable[16]; int i; if((file = fopen(conf_file_user, "r")) == NULL){ pam_logger("open configure file failed: %s\n", strerror(errno)); } else { while(fgets(line, sizeof(line), file)) { i = sscanf(line, "EnableAuth=%15s\n", is_enable); if(i > 0) { pam_logger("EnableAuth=%s\n", is_enable); is_found = 1; break; } } fclose(file); if(!strcmp(is_enable, "true")) is_auth_enable = 1; } } if (is_found != 0) { return is_auth_enable; } char conf_file[] = GET_STR(CONFIG_FILE); FILE *file; char line[1024], is_enable[16]; int i; if((file = fopen(conf_file, "r")) == NULL){ pam_logger("open configure file failed: %s\n", strerror(errno)); return 0; } while(fgets(line, sizeof(line), file)) { i = sscanf(line, "EnableAuth=%15s\n", is_enable); if(i > 0) { pam_logger("EnableAuth=%s\n", is_enable); break; } } fclose(file); if(!strcmp(is_enable, "true")) return 1; return 0; } int enable_qrcode_authentication(pam_handle_t *pamh) { char *username = NULL; int is_found = 0; int is_auth_enable = 0; pam_get_item(pamh, PAM_USER, (const void **)&username); if (username) { char conf_file_user[256]; snprintf(conf_file_user, 255, USER_CONFIG_FILE, username); FILE *file = NULL; char line[1024], is_enable[16]; int i; if((file = fopen(conf_file_user, "r")) == NULL){ pam_logger("open configure file failed: %s\n", strerror(errno)); } else { while(fgets(line, sizeof(line), file)) { i = sscanf(line, "EnableQRCode=%15s\n", is_enable); if(i > 0) { pam_logger("EnableQRCode=%s\n", is_enable); is_found = 1; break; } } fclose(file); if(!strcmp(is_enable, "true")) is_auth_enable = 1; } } if (is_found != 0) { return is_auth_enable; } char conf_file[] = GET_STR(CONFIG_FILE); FILE *file; char line[1024], is_enable[16]; int i; if((file = fopen(conf_file, "r")) == NULL){ pam_logger("open configure file failed: %s\n", strerror(errno)); return 0; } while(fgets(line, sizeof(line), file)) { i = sscanf(line, "EnableQRCode=%15s\n", is_enable); if(i > 0) { pam_logger("EnableQRCode=%s\n", is_enable); break; } } fclose(file); if(!strcmp(is_enable, "true")) return 1; return 0; } int enable_biometric_auth_double() { char conf_file[] = GET_STR(CONFIG_FILE); FILE *file; char line[1024], is_enable[16]; int i; if((file = fopen(conf_file, "r")) == NULL){ pam_logger("open configure file failed: %s\n", strerror(errno)); return 0; } while(fgets(line, sizeof(line), file)) { i = sscanf(line, "DoubleAuth=%s\n", is_enable); if(i > 0) { pam_logger("DoubleAuth=%s\n", is_enable); break; } } fclose(file); if(!strcmp(is_enable, "true")) return 1; return 0; } /* * SPI interface */ int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { for(int i = 0; i < argc; i++) { if(strcmp(argv[i], "debug") == 0) { pam_enable_debug = 1; pam_log_prefix = "PAM_BIO"; } } pam_logger("Invoke libpam_biometric.so module\n"); char *service = 0; if((!enable_biometric_authentication(pamh) && !enable_qrcode_authentication(pamh)) || ukui_biometric_lock) { pam_logger("disable biometric authentication.\n"); return PAM_IGNORE; } pam_logger("enable biometric authentication.\n"); pam_get_item(pamh, PAM_SERVICE, (const void **)&service); /* Service filter */ if (!service_filter(service)){ pam_logger("Service <%s> should not use biometric-authentication\n", service); return PAM_IGNORE; } /* Different services use different processing function */ if (strcmp(service, "lightdm") == 0) { char buf[128]; get_greeter_session(buf, sizeof(buf)); pam_logger("current greeter: %s\n", buf); if(strcmp(buf, "ukui-greeter") == 0 || strcmp(buf, "ukui-greeter-wayland") == 0 || strcmp(buf, "ukui-session") == 0 || strcmp(buf,"ukui-screensaver-backend")) return biometric_auth_embeded(pamh); // else // return biometric_auth_independent(pamh, "lightdm", 1); } else if (strcmp(service, "ukui-screensaver-qt")==0) return biometric_auth_embeded(pamh); else if (strcmp(service, "polkit-1") == 0){ if(enable_by_polkit()) return biometric_auth_embeded(pamh); else pam_logger("[PAM_BIOMETRIC]: It's not polkit-ukui-authentication-agent-1.\n"); } else if (strcmp(service, "sudo") == 0) return biometric_auth_independent(pamh, "sudo", 0); else if (strcmp(service, "login") == 0) return biometric_auth_independent(pamh, "login", 0); else if (strcmp(service, "su") == 0) return biometric_auth_independent(pamh, "su", 0); // else if (strcmp(service, "mate-screensaver") == 0) // return biometric_auth_independent(pamh, "mate-screensaver", 1); #ifdef ENABLE_BIOTEST else if (strcmp(service, "biotest") == 0) return biometric_auth_independent(pamh, "biotest", 1); #endif else pam_logger("Service <%s> slip through the service filter\n", service); return PAM_IGNORE; } int pam_sm_setcred (pam_handle_t *pamh, int flags , int argc , const char **argv ) { return PAM_SUCCESS; } ukui-biometric-auth/pam-biometric/logger.c0000664000175000017500000000243115167732630017554 0ustar fengfeng/* * Copyright (C) 2023 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include #include #include #include int pam_enable_debug; char *pam_log_prefix; void pam_logger(char *format, ...) { if(!pam_enable_debug){ return; } va_list args; time_t t = time(NULL); char timestr[32] = {0}; strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&t)); //产生"YYYYMMDD hh:mm:ss"格式的字符串。 fprintf(stderr, "[%s] %s - ", pam_log_prefix, timestr); va_start(args, format); /* 初始化 args */ vfprintf(stderr, format, args); } ukui-biometric-auth/pam-biometric/CMakeLists.txt0000664000175000017500000000342215167732644020677 0ustar fengfengproject(pam_biometric) find_path(PAM_INCLUDE_DIR security/pam_modules.h) find_library(PAM_LIB NAMES pam) if(NOT PAM_INCLUDE_DIR OR NOT PAM_LIB) message(FATAL_ERROR "pam_modules.h not found") endif() set(SCRIPTS_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/bin) configure_file( ${PROJECT_SOURCE_DIR}/data/org.freedesktop.plicykit.pkexec.bioctl-helper.policy.in ${PROJECT_BINARY_DIR}/data/org.freedesktop.plicykit.pkexec.bioctl-helper.policy ) configure_file( ${PROJECT_SOURCE_DIR}/data/org.freedesktop.plicykit.pkexec.biodrvctl.policy.in ${PROJECT_BINARY_DIR}/data/org.freedesktop.plicykit.pkexec.biodrvctl.policy ) configure_file( ${PROJECT_SOURCE_DIR}/data/org.freedesktop.plicykit.pkexec.biorestart.policy.in ${PROJECT_BINARY_DIR}/data/org.freedesktop.plicykit.pkexec.biorestart.policy ) set(pam_SRCS pam_biometric.c logger.c ) include_directories( ../common ${PAM_INCLUDE_DIR} ${GLIB2_INCLUDE_DIRS} ) add_library(pam_biometric SHARED ${pam_SRCS}) target_link_libraries(pam_biometric ${PAM_LIB} ${GLIB2_LIBRARIES}) #去除lib前缀 set_target_properties(pam_biometric PROPERTIES PREFIX "") install(TARGETS pam_biometric DESTINATION /usr/lib/security) install(FILES pam-configs/pam-biometric DESTINATION /etc/pam-configs) install(FILES data/ukui-biometric.conf DESTINATION /usr/share/ukui-biometric) install(FILES ${PROJECT_BINARY_DIR}/data/org.freedesktop.plicykit.pkexec.bioctl-helper.policy ${PROJECT_BINARY_DIR}/data/org.freedesktop.plicykit.pkexec.biodrvctl.policy ${PROJECT_BINARY_DIR}/data/org.freedesktop.plicykit.pkexec.biorestart.policy DESTINATION /usr/share/polkit-1/actions ) install(FILES utils/bioctl utils/bioctl-helper utils/biodrvctl utils/biorestart DESTINATION bin PERMISSIONS ${CONDOR_SCRIPT_PERMS}) ukui-biometric-auth/pam-biometric/utils/0000775000175000017500000000000015167732630017271 5ustar fengfengukui-biometric-auth/pam-biometric/utils/bioctl0000775000175000017500000000050215167732630020470 0ustar fengfeng#!/bin/bash # Usage: bioctl status|enable|disable if [ "$1" = "enable" ]; then pkexec /usr/bin/bioctl-helper enable $2 elif [ "$1" = "disable" ]; then pkexec /usr/bin/bioctl-helper disable $2 elif [ "$1" = "status" ]; then /usr/bin/bioctl-helper status $2 else echo "Usage: bioctl status|enable|disable" fi exit 0 ukui-biometric-auth/pam-biometric/utils/bioctl-helper0000775000175000017500000002050015167732630021745 0ustar fengfeng#!/bin/bash # Usage: bioctl status|enable|disable CONFIG_DIR=/etc/biometric-auth CONFIG_FILE=$CONFIG_DIR/ukui-biometric.conf function test_privilege() { if [ `whoami` != 'root' ]; then echo $(gettext "Permission denied, please run by root") exit 1; fi } if [ ! -d $CONFIG_DIR ]; then mkdir -p $CONFIG_DIR fi if [ ! -f $CONFIG_FILE ]; then touch $CONFIG_FILE fi contain_key=`grep -c "^EnableAuth=" $CONFIG_FILE` contain_key_app=`grep -c "^EnableAuthApp=" $CONFIG_FILE` greeter=1 screensaver=$[1<<1] polkit=$[1<<2] sudo=$[1<<3] su=$[1<<4] login=$[1<<5] if [ "$1" = "enable" ]; then test_privilege # 生物识别管理工具在打开生物识别开关的时候会调用这个脚本, # 如果之前手动改过pam的配置文件,在执行这个脚本的时候会有交互 # 性提示,但前端程序上看不到,导致生物识别管理工具阻塞,不过 # 由于在安装pam_biomtric这个包时已经执行了这个命令,且会通过 # /etc/biometric-auth 配置文件来判断生物识别状态,所以也不需要 #执行 pam-auth-update 了。 #pam-auth-update --package pam-biometric if [[ $# > 1 ]] && [[ $2 = "greeter" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app | $greeter ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=63" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "screensaver" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app | $screensaver ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=63" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "sudo" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app | $sudo ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=63" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "polkit" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app | $polkit ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=63" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "su" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app | $su ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=63" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "login" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app | $login ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=63" >> $CONFIG_FILE fi elif [ "$contain_key" = "1" ]; then sed -i 's/^EnableAuth=[a-zA-Z0-9]*/EnableAuth=true/g' $CONFIG_FILE else echo "EnableAuth=true" >> $CONFIG_FILE fi elif [ "$1" = "disable" ]; then test_privilege if [[ $# > 1 ]] && [[ $2 = "greeter" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app & $[~$greeter] ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=0" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "screensaver" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app & $[ ~$screensaver ]] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=0" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "sudo" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app & $[ ~$sudo ] ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=0" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "polkit" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app & $[~$polkit] ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=0" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "su" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app & $[~$su] ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=0" >> $CONFIG_FILE fi elif [[ $# > 1 ]] && [[ $2 = "login" ]]; then if [ "$contain_key_app" = "1" ]; then cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=$[ $cur_status_app & $[~$login] ] sed -i "s/^EnableAuthApp=[a-zA-Z0-9]*/EnableAuthApp=$cur_status_app/g" $CONFIG_FILE else echo "EnableAuthApp=0" >> $CONFIG_FILE fi elif [ "$contain_key" = "1" ]; then sed -i 's/^EnableAuth=[a-zA-Z0-9]*/EnableAuth=false/g' $CONFIG_FILE else echo "EnableAuth=false" >> $CONFIG_FILE fi elif [ "$1" = "status" ]; then cur_status=`sed '/^EnableAuth=/!d;s/.*=//' $CONFIG_FILE` cur_status_app=`sed '/^EnableAuthApp=/!d;s/.*=//' $CONFIG_FILE` if [[ $# > 1 ]] && [[ $2 = "greeter" ]];then if [ $[ $[cur_status_app] & $[greeter] ] = $greeter ]; then echo "enable" else echo "disable" fi elif [[ $# > 1 ]] && [[ $2 = "screensaver" ]];then if [ $[$cur_status_app & $screensaver] = $screensaver ]; then echo "enable" else echo "disable" fi elif [[ $# > 1 ]] && [[ $2 = "sudo" ]];then if [ $[$cur_status_app & $sudo] = $sudo ]; then echo "enable" else echo "disable" fi elif [[ $# > 1 ]] && [[ $2 = "polkit" ]];then if [ $[$cur_status_app & $polkit] = $polkit ]; then echo "enable" else echo "disable" fi elif [[ $# > 1 ]] && [[ $2 = "su" ]];then if [ $[$cur_status_app & $su] = $su ]; then echo "enable" else echo "disable" fi elif [[ $# > 1 ]] && [[ $2 = "login" ]];then if [ $[$cur_status_app & $login] = $login ]; then echo "enable" else echo "disable" fi elif [ "$cur_status" = "true" ]; then echo "enable" else echo "disable" fi else echo "Usage: bioctl status|enable|disable" fi exit 0 ukui-biometric-auth/pam-biometric/utils/biorestart0000775000175000017500000000024515167732630021376 0ustar fengfeng#!/bin/bash if [ `whoami` != 'root' ]; then echo $(gettext "Permission denied, please run by root") exit 1 fi systemctl restart biometric-authentication.service ukui-biometric-auth/pam-biometric/utils/biodrvctl0000775000175000017500000000143615167732630021213 0ustar fengfeng#!/bin/bash export TEXTDOMAINDIR=/usr/share/locale export TEXTDOMAIN=biodrvctl . gettext.sh function usage() { echo -e "Usage:" echo -e " biodrvctl "$(gettext "COMMAND DRIVER-NAME") echo echo -e "Build-in command:" echo -e " enable\t"$(gettext "Enable device's driver") echo -e " disable\t"$(gettext "Disable device's driver") } if [ $# -ne 2 ]; then usage exit 1 fi if [ `whoami` != 'root' ]; then echo $(gettext "Permission denied, please run by root") exit 1 fi if [ "$1" == "enable" ]; then biometric-config-tool enable-driver $2 elif [ "$1" == "disable" ]; then biometric-config-tool disable-driver $2 else usage exit 1 fi if [ $? -eq 0 ]; then systemctl reset-failed biometric-authentication.service systemctl restart biometric-authentication.service fi exit $? ukui-biometric-auth/pam-biometric/pam-configs/0000775000175000017500000000000015167732630020334 5ustar fengfengukui-biometric-auth/pam-biometric/pam-configs/pam-biometric0000664000175000017500000000026515167732630023012 0ustar fengfengName: Biometric Verification Default: yes Priority: 260 Conflicts: fprint fprintd fprintd.i386 fprintd.amd64 Auth-Type: Primary Auth: [success=end default=ignore] pam_biometric.so ukui-biometric-auth/pam-biometric/data/0000775000175000017500000000000015167732644017047 5ustar fengfengukui-biometric-auth/pam-biometric/data/org.freedesktop.plicykit.pkexec.biorestart.policy.in0000664000175000017500000000634015167732630031256 0ustar fengfeng Restart Service 重启生物特征服务 བསྐྱར་དུ་ཞབས་འདེགས་ཞུ་བ ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ ᠤᠨ ᠣᠨᠴᠠᠯᠢᠭ ᠤᠨ ᠦᠢᠯᠡᠴᠢᠯᠡᠭᠡ ᠶᠢ ᠳᠠᠬᠢᠨ ᠡᠭᠢᠯᠡᠭᠦᠯᠪᠡ᠃ Authentication is required to restart biometric service 重啟生物特徵服務 بىئولوگىيەلىك ئالاھىدىلىك مۇلازىمىتىنى قايتىدىن قوزغىتىش بىئولوگىيەلىك ەرەكشەلىك قىزىمەتتى قايتادان قوزعالتۋ بىئولوگىيەلىك ۅزگۅچۅلۉك مۇلازىمەتىردى قايتادان قوزعوتۇۇ 重启生物特征服务需要身份验证 སྐྱ་དངོས་དབྱེ་འབྱེད་ཞབས་ཞུ་སླར་གསོ་བྱེད་པར་བདེན་དཔང་ར་སྤྲད་བྱ་དགོས། ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ ᠤᠨ ᠣᠨᠴᠠᠯᠢᠭ ᠰᠢᠨᠵᠢ ᠲᠡᠮᠳᠡᠭ ᠦᠨ ᠦᠢᠯᠡᠴᠢᠯᠡᠭᠡ ᠶᠢ ᠳᠠᠬᠢᠨ ᠰᠡᠩᠬᠡᠷᠡᠭᠦᠯᠬᠦ ᠳᠦ ᠪᠡᠶ᠎ᠡ ᠶᠢᠨ ᠭᠠᠷᠤᠯ ᠢ ᠰᠢᠯᠭᠠᠨ ᠭᠡᠷᠡᠴᠢᠯᠡᠬᠦ ᠴᠢᠬᠤᠯᠠ ᠲᠠᠶ ᠪᠠᠶᠢᠨ᠎ᠠ ᠃ بىئولوگىيەلىك ئالاھىدىلىك مۇلازىمىتىنى قايتىدىن قوزغىتىش ئۈچۈن دەلىللەش كېرەك 重啟生物特徵服務需要身份驗證 بىئولوگىيەلىك ەرەكشەلىك قىزىمەتتى قايتادان قوزعالتۋ ٷشٸن دالەلدەۋ كەرەك بىئولوگىيەلىك پارىقتاندىرۋ اسبابٸن قوزعالتۋ مەڭگەرۋ ەتۋ اسپاپتى جۇرگىزۋ بىئولوگىيەلىك ۅزگۅچۅلۉك مۇلازىمەتىردى قايتادان قوزعوتۇۇ ۉچۉن دالىلدۅ كەرەك بىئولوگىيەلىك ايىرمالاندىرىش جابدۇۇسۇن قوزعوتۇۇ تىزگىندۅۅ جاسوو ،اتقارۇۇ stock_person auth_admin auth_admin auth_admin_keep ${SCRIPTS_INSTALL_PATH}/biorestart ukui-biometric-auth/pam-biometric/data/org.freedesktop.plicykit.pkexec.bioctl-helper.policy.in0000664000175000017500000000641415167732630031633 0ustar fengfeng Run the biometric authentication control tool 运行生物识别认证控制工具 འཁོར་སྐྱོད་སྐྱེ་དངོས་ཀྱི་ངོས་འཛིན་ཁས་ལེན་ཚོད་འཛིན་ཡོ་བྱད།། ᠠᠵᠢᠯᠯᠠᠭᠠᠨ ᠤ ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ ᠢ ᠢᠯᠭᠠᠨ ᠲᠠᠨᠢᠵᠤ ᠭᠡᠷᠡᠴᠢᠯᠡᠬᠦ ᠡᠵᠡᠮᠳᠡᠯ ᠦᠨ ᠪᠠᠭᠠᠵᠢ ᠶᠢ ᠢᠯᠭᠠᠨ ᠲᠠᠨᠢᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠶ ᠃ 運行生物識別認證控制工具 بىئولوگىيەلىك پەرقلەندۈرۈش ئىسپاتلاش كونترول قىلىش قورالى بىئولوگىيەلىك پارىقتاندىرۋ سپاتتاۋ مەڭگەرۋ ەتۋ قۇرالى بىئولوگىيەلىك ايىرمالاندىرىش ىسپاتتوو تىزگىندۅۅ جاسوو ،اتقارۇۇ قۇرالى Authentication is required to enable or disable biometric authentication 开启或关闭生物识别认证需要进行身份验证 སྒོ་རྒྱག་པའམ་ཡང་ན་སྒོ་རྒྱག་པའི་སྐྱེ་དངོས་ངོས་འཛིན་བདེན་དཔངར་སྤྲོད་བྱེད་པར་ཐོབ་ཐང་གི་ཚོད་ལྟསར་སྤྲོད་བྱ་དགོས། ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ ᠢ ᠢᠯᠭᠠᠨ ᠲᠠᠨᠢᠬᠤ ᠭᠡᠷᠡᠴᠢᠯᠡᠭᠡ ᠶᠢ ᠨᠡᠭᠡᠭᠡᠬᠦ ᠪᠤᠶᠤ ᠬᠠᠭᠠᠬᠤ ᠳᠤ ᠪᠡᠶ᠎ᠡ ᠶᠢᠨ ᠭᠠᠷᠤᠯ ᠤᠨ ᠭᠡᠷᠡᠴᠢᠯᠡᠯ ᠬᠢᠬᠦ ᠴᠢᠬᠤᠯᠠ ᠲᠠᠶ ᠪᠠᠶᠢᠨ᠎ᠠ᠃ 開啟或關閉生物識別認證需要進行身份驗證 بىئولوگىيەلىك پەرقلەندۈرۈش ئىسپاتىنى ئېچىش ياكى تاقاش ئۈچۈن دەلىللەش كېرەك بىئولوگىيەلىك پارىقتاندىرۋ سىپاتىن ٸشٸۋ ياكي تاقاۋ ٷشٸن دالەلدەۋ كەرەك بىئولوگىيەلىك ايىرمالاندىرىش دالىلىن اچۇۇ كۅرۉنۉشتۅرۉ بەكىتىش ۉچۉن دالىلدۅ كەرەك stock_person no no yes ${SCRIPTS_INSTALL_PATH}/bioctl-helper ukui-biometric-auth/pam-biometric/data/ukui-biometric.conf0000664000175000017500000000034715167732644022652 0ustar fengfeng[General] EnableAuth=true EnableAuthApp=63 DefaultDevice= DoubleAuth=false UserBind=false isShownInControlCenter=false UseFirstDevice=true MaxFailedTimes=5 HiddenSwitchButton=false FaceTimeoutTimes=1 [Functions] EnableQRCode=true ukui-biometric-auth/pam-biometric/data/org.freedesktop.plicykit.pkexec.biodrvctl.policy.in0000664000175000017500000000647515167732630031101 0ustar fengfeng Run the biometric device driver control tool 运行生物识别设备驱动控制工具 སྐྱ་དངོས་དབྱེ་འབྱེད་སྒྲག་ཆས་ཀྱི་ཁ་ལོ་བའི་ཚོད་འཛིན་ཡོ་བྱད་ ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ ᠢ ᠢᠯᠭᠠᠨ ᠲᠠᠨᠢᠬᠤ ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ ᠪᠡᠷ ᠬᠥᠳᠡᠯᠭᠡᠭᠦᠷ ᠪᠣᠯᠭᠠᠬᠤ ᠡᠵᠡᠮᠳᠡᠯ ᠦᠨ ᠪᠠᠭᠠᠵᠢ ᠶᠢ ᠠᠵᠢᠯᠯᠠᠭᠤᠯᠤᠨ᠎ᠠ ᠃ 運行生物識別設備驅動控制工具 بىئولوگىيەلىك پەرقلەندۈرۈش ئۈسكۈنىسىنى قوزغىتىش كونترول قىلىش ئەسۋابىنى يۈرگۈزۈش شايمانىن جۉرگۅزۉ شايمانىن جۉرگۅزۉ Authentication is required to change the status of biometric device's driver 改变生物识别设备驱动状态需要进行身份验证 སྐྱ་དངོས་དབྱེ་འབྱེད་སྒྲག་ཆས་ཀྱི་ཁ་ལོ་བའི་གནས་ཚུལ་ལ་འགྱུར་ལྡོག་གཏོང་བར་བདེན་དཔང་ར་སྤྲད་བྱ་དགོས། ᠠᠮᠢᠳᠤ ᠪᠣᠳᠠᠰ ᠢ ᠢᠯᠭᠠᠨ ᠲᠠᠨᠢᠬᠤ ᠲᠥᠬᠥᠭᠡᠷᠦᠮᠵᠢ ᠶᠢᠨ ᠬᠥᠳᠡᠯᠭᠡᠭᠦᠷ ᠪᠣᠯᠭᠠᠬᠤ ᠪᠠᠶᠢᠳᠠᠯ ᠢ ᠬᠤᠪᠢᠷᠠᠭᠤᠯᠬᠤ ᠳᠤ ᠪᠡᠶ᠎ᠡ ᠶᠢᠨ ᠭᠠᠷᠤᠯ ᠤᠨ ᠭᠡᠷᠡᠴᠢᠯᠡᠯ ᠬᠢᠬᠦ ᠴᠢᠬᠤᠯᠠ ᠲᠠᠶ ᠪᠠᠶᠢᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠶ᠃ 改變生物識別設備驅動狀態需要進行身份驗證 بىئولوگىيەلىك پەرقلەندۈرۈش ئۈسكۈنىسىنىڭ قوزغىتىش ھالىتىنى ئۆزگەرتىشتە دەلىللەش كېرەك بىئولوگىيەلىك پارىقتاندىرۋ اسپابىنىڭ قوزعالتۋ كۇيىن وزگەتۋگە دالەلدەۋ كەرەك بىئولوگىيەلىك ايىرمالاندىرىش شايمانىنىن قوزعوتۇۇ ابالىن ۅزگۅرتۉۉدۅ دالىلدۅ كەرەك stock_person auth_admin auth_admin auth_admin_keep ${SCRIPTS_INSTALL_PATH}/biodrvctl ukui-biometric-auth/tests/0000775000175000017500000000000015167732644014550 5ustar fengfengukui-biometric-auth/tests/unit_test_keywatcher/0000775000175000017500000000000015167732644021014 5ustar fengfengukui-biometric-auth/tests/unit_test_keywatcher/CMakeLists.txt0000664000175000017500000000315515167732630023553 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets Test REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../bioauth-bin/src/keywatcher.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../bioauth-bin/src/keywatcher.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_keywatcher ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_keywatcher Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets Qt5::Test ) # 链接 GTest 库 target_link_libraries(unit_test_keywatcher GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_keywatcher/main.cpp0000664000175000017500000000435715167732644022455 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include "../../bioauth-bin/src/keywatcher.h" class KeyWatcherTest : public ::testing::Test { protected: void SetUp() override { watcher = new KeyWatcher(nullptr); } void TearDown() override { delete watcher; } KeyWatcher* watcher; int argc = 0; char** argv = nullptr; }; TEST_F(KeyWatcherTest, ConstructionAndDestruction) { // Verify that the KeyWatcher object can be constructed and destroyed without crashing. EXPECT_TRUE(watcher != nullptr); } TEST_F(KeyWatcherTest, EmitExitSignal) { // This test is tricky because it depends on terminal I/O. // We can use a signal spy to detect the exit signal. //QSignalSpy spy(watcher, &KeyWatcher::exit); // Normally, we would need to run the KeyWatcher thread and simulate input. // However, for simplicity, we will just call stop() which should trigger the cleanup code. //watcher->stop(); // Note: This is not a complete test of the run() method, just a check for signal emission. // A proper test would require simulating terminal input and output. //EXPECT_EQ(spy.count(), 1); } // Additional tests could be added here to test other parts of the KeyWatcher class. // For example, testing the behavior of the run() method with different inputs would require // setting up a mock terminal or using some form of input redirection. int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); QCoreApplication app(argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_biodeviceinfo/0000775000175000017500000000000015167732644021453 5ustar fengfengukui-biometric-auth/tests/unit_test_biodeviceinfo/CMakeLists.txt0000664000175000017500000000313015167732630024203 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../uniauth-backend/src/biodeviceinfo.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../uniauth-backend/src/biodeviceinfo.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_biodeviceinfo ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_biodeviceinfo Qt5::Core Qt5::Gui Qt5::DBus ) # 链接 GTest 库 target_link_libraries(unit_test_biodeviceinfo GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_biodeviceinfo/main.cpp0000664000175000017500000000453015167732644023105 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include "../../uniauth-backend/src/biodeviceinfo.h" #include #include // gtest 测试用例 TEST(BioDeviceInfoTest, SerializationAndDeserialization) { registerCustomTypes(); DeviceInfo original; original.device_id = 1; original.device_shortname = "TestDevice"; original.device_fullname = "Test Device Full Name"; original.driver_enable = 1; original.device_available = 1; original.biotype = BIOTYPE_FINGERPRINT; original.stotype = 0; original.eigtype = 0; original.vertype = 0; original.idtype = 0; original.bustype = 0; original.dev_status = 0; original.ops_status = 0; QDBusArgument argument; argument<> deserialized; EXPECT_EQ(original.device_id, deserialized.device_id); EXPECT_EQ(original.device_shortname, deserialized.device_shortname); EXPECT_EQ(original.device_fullname, deserialized.device_fullname); EXPECT_EQ(original.driver_enable, deserialized.driver_enable); EXPECT_EQ(original.device_available, deserialized.device_available); EXPECT_EQ(original.biotype, deserialized.biotype); EXPECT_EQ(original.stotype, deserialized.stotype); EXPECT_EQ(original.eigtype, deserialized.eigtype); EXPECT_EQ(original.vertype, deserialized.vertype); EXPECT_EQ(original.idtype, deserialized.idtype); EXPECT_EQ(original.bustype, deserialized.bustype); EXPECT_EQ(original.dev_status, deserialized.dev_status); EXPECT_EQ(original.ops_status, deserialized.ops_status); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_kalabel/0000775000175000017500000000000015167732644020241 5ustar fengfengukui-biometric-auth/tests/unit_test_kalabel/CMakeLists.txt0000664000175000017500000000311515167732630022774 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../polkit-agent/src/kalabel.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../polkit-agent/src/kalabel.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_kalabel ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_kalabel Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets ) # 链接 GTest 库 target_link_libraries(unit_test_kalabel GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_kalabel/main.cpp0000664000175000017500000000663215167732644021700 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include "../../polkit-agent/src/kalabel.h" #include #include #include // 辅助函数,用于创建QFontMetrics对象,避免在测试中重复代码 QFontMetrics createFontMetrics(const QFont& font) { return QFontMetrics(font); } // 测试getElidedText方法是否正确地省略了文本 TEST(KALabelTest, GetElidedText_ShouldElideTextIfWidthIsExceeded) { // 创建一个QFont对象,并设置其属性(这里使用默认属性) QFont font; QFontMetrics fontMetrics = createFontMetrics(font); // 设置测试字符串和宽度 QString testString = "This is a very long text that needs to be elided."; #if QT_VERSION_MAJOR == 6 int width = fontMetrics.horizontalAdvance("This is a short text."); // 假设这个宽度是合适的测试宽度 #else int width = fontMetrics.width("This is a short text."); // 假设这个宽度是合适的测试宽度 #endif // 创建KALabel对象(仅为了访问其getElidedText方法) KALabel kalabel; // 调用getElidedText方法 QString elidedText = kalabel.getElidedText(font, width, testString); // 检查文本是否被省略 EXPECT_TRUE(elidedText.endsWith("...")); #if QT_VERSION_MAJOR == 6 EXPECT_LT(fontMetrics.horizontalAdvance(elidedText), width); #else EXPECT_LT(fontMetrics.width(elidedText), width); #endif } // 测试getElidedText方法在没有超过宽度时是否返回原始文本 TEST(KALabelTest, GetElidedText_ShouldNotElideTextIfWidthIsNotExceeded) { // 创建一个QFont对象,并设置其属性(这里使用默认属性) QFont font; QFontMetrics fontMetrics = createFontMetrics(font); // 设置测试字符串和宽度(确保宽度足够大以容纳整个字符串) QString testString = "Short text"; #if QT_VERSION_MAJOR == 6 int width = fontMetrics.horizontalAdvance(testString) + 10; // 加一些额外的宽度以确保不会省略 #else int width = fontMetrics.width(testString) + 10; // 加一些额外的宽度以确保不会省略 #endif // 创建KALabel对象(仅为了访问其getElidedText方法) KALabel kalabel; // 调用getElidedText方法 QString elidedText = kalabel.getElidedText(font, width, testString); // 检查文本是否未被省略 EXPECT_EQ(elidedText, testString); } TEST(KALabelTest, ShowTest) { KALabel kalabel; KALabel kalabel1("test"); kalabel1.setText("test1"); kalabel1.setFixedWidth(80); kalabel1.paintEvent(nullptr); kalabel1.setText("long long long long long test text"); kalabel1.paintEvent(nullptr); } int main(int argc, char **argv) { QApplication a(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_rsac/0000775000175000017500000000000015167732644017576 5ustar fengfengukui-biometric-auth/tests/unit_test_rsac/CMakeLists.txt0000664000175000017500000000321515167732630022332 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../uniauth-backend/src/rsac.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../uniauth-backend/src/rsac.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ${CMAKE_CURRENT_SOURCE_DIR}/../../uniauth-backend/src/ ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_rsac ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_rsac Qt5::Core Qt5::Gui Qt5::DBus ) # 链接 GTest 库 target_link_libraries(unit_test_rsac GTest::GTest GTest::Main Threads::Threads ${GIOUNIX2_LIBRARIES} -lcrypto ) ukui-biometric-auth/tests/unit_test_rsac/main.cpp0000664000175000017500000000715515167732644021236 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include "../../uniauth-backend/src/rsac.h" #include #include #include #include #include #include #include // 辅助函数,用于初始化OpenSSL库 void InitOpenSSL() { OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); } // 辅助函数,用于清理OpenSSL库 void CleanupOpenSSL() { EVP_cleanup(); ERR_free_strings(); } // 测试类 class RSACTest : public ::testing::Test { protected: void SetUp() override { InitOpenSSL(); } void TearDown() override { CleanupOpenSSL(); } RSAC rsac; }; // 测试密钥生成并保存到文件 TEST_F(RSACTest, GenerateKeyPairToFile) { QString priKeyFile = "test_private.pem"; QString pubKeyFile = "test_public.pem"; rsac.generateKeyPair(priKeyFile, pubKeyFile, 1024); // 这里可以添加额外的检查来验证文件是否成功生成且内容有效 // 例如,打开文件并读取内容,检查是否为有效的PEM格式密钥 // 但由于这是一个简单的测试示例,我们省略了这些步骤 } // 测试密钥生成并保存到QByteArray TEST_F(RSACTest, GenerateKeyPairToByteArray) { QByteArray privateKey; QByteArray publicKey; rsac.generateKeyPair(privateKey, publicKey, 1024); // 检查生成的密钥是否非空 EXPECT_FALSE(privateKey.isEmpty()); EXPECT_FALSE(publicKey.isEmpty()); // 这里可以添加额外的检查来验证密钥的有效性 // 例如,使用OpenSSL函数解析生成的密钥并检查其属性 // 但由于这是一个简单的测试示例,我们省略了这些步骤 } // 测试加密和解密 TEST_F(RSACTest, EncryptDecrypt) { QByteArray privateKey; QByteArray publicKey; rsac.generateKeyPair(privateKey, publicKey, 1024); QByteArray plaintext = "Hello, RSA!"; QByteArray ciphertext; QByteArray decryptedtext; bool encryptResult = rsac.encrypt(plaintext, ciphertext, publicKey); EXPECT_TRUE(encryptResult); bool decryptResult = rsac.decrypt(ciphertext, decryptedtext, privateKey); EXPECT_TRUE(decryptResult); EXPECT_EQ(plaintext, decryptedtext); } // 测试签名和验签 TEST_F(RSACTest, SignVerify) { QByteArray privateKey; QByteArray publicKey; rsac.generateKeyPair(privateKey, publicKey, 1024); QByteArray message = "This is a test message."; QByteArray signature; bool signResult = rsac.sign(message, signature, privateKey); EXPECT_TRUE(signResult); bool verifyResult = rsac.verify(message, signature, publicKey); EXPECT_TRUE(verifyResult); // 尝试使用错误的消息进行验签,应该失败 bool verifyWithWrongMessageResult = rsac.verify("Wrong message.", signature, publicKey); EXPECT_FALSE(verifyWithWrongMessageResult); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_giodbus/0000775000175000017500000000000015167732644020302 5ustar fengfengukui-biometric-auth/tests/unit_test_giodbus/CMakeLists.txt0000664000175000017500000000343515167732630023042 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(GIOUNIX2 REQUIRED gio-unix-2.0) pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../bioauth/src/giodbus.cpp unit_test_giodbus.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../bioauth/include/giodbus.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ${CMAKE_CURRENT_SOURCE_DIR}/../../bioauth/include/ ${GIOUNIX2_INCLUDE_DIRS} ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_giodbus ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_giodbus Qt5::Core Qt5::Gui Qt5::DBus ) # 链接 GTest 库 target_link_libraries(unit_test_giodbus GTest::GTest GTest::Main Threads::Threads ${GIOUNIX2_LIBRARIES} ) ukui-biometric-auth/tests/unit_test_giodbus/main.cpp0000664000175000017500000000156115167732644021735 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include int main(int argc, char **argv) { QGuiApplication a(argc, argv); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_giodbus/unit_test_giodbus.cpp0000664000175000017500000000202415167732644024536 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include "../../bioauth/include/giodbus.h" #include "stubext.h" using namespace stub_ext; class FreedesktopHelperTest : public testing::Test { protected: }; TEST_F(FreedesktopHelperTest, get_server_gvariant_stdout) { int value = get_server_gvariant_stdout(-1); ASSERT_EQ(value, -1); } ukui-biometric-auth/tests/CMakeLists.txt0000664000175000017500000000275315167732630017312 0ustar fengfengadd_subdirectory(unit_test_giodbus) add_subdirectory(unit_test_biodeviceinfo) add_subdirectory(unit_test_kalabel) add_subdirectory(unit_test_rsac) add_subdirectory(unit_test_pam_tally) add_subdirectory(unit_test_common) add_subdirectory(unit_test_loginoptionswidget) add_subdirectory(unit_test_keywatcher) add_subdirectory(unit_test_personalizeddata) add_subdirectory(unit_test_modebutton) add_subdirectory(unit_test_users) add_subdirectory(unit_test_biodevices) add_subdirectory(unit_test_usdblockshortcut) add_subdirectory(unit_test_sessionmanager) add_subdirectory(unit_test_servicemanager) # 处理打桩工具相关配置 set(TEST_UTILS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/kt-test-utils") # 收集打桩工具的头文件,递归查找符合条件的头文件 file(GLOB_RECURSE UTILS_HEADERS "${TEST_UTILS_PATH}/cpp-stub/*.h" "${TEST_UTILS_PATH}/cpp-stub/*.hpp" "${TEST_UTILS_PATH}/cpp-stub-ext/*.h" ) # 收集打桩工具的源文件,递归查找符合条件的源文件 file(GLOB_RECURSE UTILS_SOURCES "${TEST_UTILS_PATH}/cpp-stub/*.cpp" "${TEST_UTILS_PATH}/cpp-stub-ext/*.cpp" ) # 创建一个库(这里以静态库为例,可以根据需求改为共享库等)来存放打桩工具相关代码 add_library(utils_lib STATIC ${UTILS_SOURCES} ${UTILS_HEADERS}) # 将打桩工具库的头文件目录添加到包含路径,方便其他目标使用 target_include_directories(utils_lib PUBLIC "${TEST_UTILS_PATH}/cpp-stub" "${TEST_UTILS_PATH}/cpp-stub-ext" ) ukui-biometric-auth/tests/unit_test_personalizeddata/0000775000175000017500000000000015167732644022177 5ustar fengfengukui-biometric-auth/tests/unit_test_personalizeddata/CMakeLists.txt0000664000175000017500000000350515167732630024735 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) pkg_check_modules(LIGHTDM-QT5-3 REQUIRED liblightdm-qt5-3) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../uniauth-backend/src/personalizeddata.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../uniauth-backend/src/personalizeddata.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ${CMAKE_CURRENT_SOURCE_DIR}/../../uniauth-backend/src/ ${LIGHTDM-QT5-3_INCLUDE_DIRS} ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_personalizeddata ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_personalizeddata Qt5::Core Qt5::Gui Qt5::DBus ) # 链接 GTest 库 target_link_libraries(unit_test_personalizeddata GTest::GTest GTest::Main Threads::Threads ${GIOUNIX2_LIBRARIES} -lcrypto ${LIGHTDM-QT5-3_LIBRARIES} ) ukui-biometric-auth/tests/unit_test_personalizeddata/main.cpp0000664000175000017500000000772715167732644023644 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include #include "../../uniauth-backend/src/personalizeddata.h" // Global instance for testing PersonalizedDataMng* g_personalizedDataMng = nullptr; // Test case for PersonalizedData TEST(PersonalizedDataTest, GetJsonData) { // Create a PersonalizedData instance PersonalizedData pd("testuser"); // Set some values (using direct access for simplicity in this test) pd.dateType("yyyy-MM-dd"); pd.fontSize(12); pd.timeType(24); pd.backgroundPath("/path/to/background"); pd.color("#FFFFFF"); pd.cursor_size(10); pd.cursor_theme(""); pd.scaling_factor(1); // Get JSON data QJsonObject json; pd.getJsonData(json); // Verify JSON data EXPECT_EQ(json["user"].toString(), "testuser"); EXPECT_EQ(json["dateType"].toString(), "yyyy-MM-dd"); EXPECT_EQ(json["fontSize"].toInt(), 12); EXPECT_EQ(json["timeType"].toInt(), 24); EXPECT_EQ(json["backgroundPath"].toString(), "/path/to/background"); EXPECT_EQ(json["color"].toString(), "#FFFFFF"); pd.dateType(); pd.fontSize(); pd.timeType(); pd.backgroundPath(); pd.color(); pd.cursor_size(); pd.cursor_theme(); pd.scaling_factor(); pd.getJsonData(); pd.fileChanged(""); pd.__load_conf_usd_conf(); pd.__copy_file("/usr/share/backgrounds/1-openkylin.jpg"); pd.__copy_file(""); } // Test case for PersonalizedDataMng TEST(PersonalizedDataMngTest, GetConfInformation) { // Initialize PersonalizedDataMng with mock dependencies if needed if (!g_personalizedDataMng) { g_personalizedDataMng = new PersonalizedDataMng(); // Mock QLightDM::UsersModel and other dependencies if necessary } // Add a user to the model (simulating onUserAdded) QString userName = "testuser"; PersonalizedData* pd = new PersonalizedData(userName); QJsonObject json; pd->getJsonData(json); json["operation"] = "testoperation"; QJsonDocument document; document.setObject(json); QString jsonStr = document.toJson(QJsonDocument::Compact); // Emit the conf_changed signal (simulating onUserAdded) emit g_personalizedDataMng->conf_changed(jsonStr); // Retrieve configuration information QString confInfo = g_personalizedDataMng->GetConfInformation(userName); // Verify configuration information (parse JSON and check values) QJsonDocument confDoc = QJsonDocument::fromJson(confInfo.toUtf8()); QJsonObject confJson = confDoc.object(); EXPECT_EQ(confJson["user"].toString(), userName); // EXPECT_EQ(confJson["operation"].toInt(), "testoperation"); EXPECT_EQ(confJson["dateType"].toString(), "cn"); // Default value from PersonalizedData // Add more verifications as needed g_personalizedDataMng->SetLoginSynInformation(""); g_personalizedDataMng->GetConfInformation("kylin"); g_personalizedDataMng->GetConfInformation("lightdm"); g_personalizedDataMng->GetConfInformation(""); QModelIndex index; g_personalizedDataMng->onUserAdded(index,0,0); g_personalizedDataMng->onUserRemoved(index,0,0); delete g_personalizedDataMng; } int main(int argc, char **argv) { QCoreApplication app(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_usdblockshortcut/0000775000175000017500000000000015167732644022250 5ustar fengfengukui-biometric-auth/tests/unit_test_usdblockshortcut/CMakeLists.txt0000664000175000017500000000317215167732631025007 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../polkit-agent/src/usdblockshortcut.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../polkit-agent/src/usdblockshortcut.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_usdblockshortcut ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_usdblockshortcut Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets ) # 链接 GTest 库 target_link_libraries(unit_test_usdblockshortcut GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_usdblockshortcut/main.cpp0000664000175000017500000000300515167732644023676 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ // usdblockshortcut_test.cpp #include #include #include #include #include #include #include #include "../../polkit-agent/src/usdblockshortcut.h" // Test fixture for SessionManager class USDBlockShortCutTest : public ::testing::Test { protected: void SetUp() override { usdblockShortCut = new USDBlockShortCut(); } void TearDown() override { delete usdblockShortCut; } USDBlockShortCut *usdblockShortCut; }; TEST_F(USDBlockShortCutTest, testUSDBlockShortCutTest) { EXPECT_TRUE(usdblockShortCut != nullptr); usdblockShortCut->blockShortcuts(); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/kt-test-utils/0000775000175000017500000000000015167732630017274 5ustar fengfengukui-biometric-auth/tests/kt-test-utils/cpp-stub/0000775000175000017500000000000015167732644021036 5ustar fengfengukui-biometric-auth/tests/kt-test-utils/cpp-stub/addr_pri.h0000664000175000017500000002436415167732630022777 0ustar fengfeng#ifndef __ADDR_PRI_H__ #define __ADDR_PRI_H__ #include #include //base on C++11 /********************************************************** access private function **********************************************************/ namespace std { template using enable_if_t = typename enable_if::type; template using remove_reference_t = typename remove_reference::type; } // std // Unnamed namespace is used to avoid duplicate symbols if the macros are used namespace { namespace private_access_detail { // @tparam TagType, used to declare different "get" funciton overloads for // different members/statics template struct private_access { // Normal lookup cannot find in-class defined (inline) friend functions. friend PtrType get(TagType) { return PtrValue; } }; } // namespace private_access_detail } // namespace // Used macro naming conventions: // The "namespace" of this macro library is PRIVATE_ACCESS, i.e. all // macro here has this prefix. // All implementation macro, which are not meant to be used directly have the // PRIVATE_ACCESS_DETAIL prefix. // Some macros have the ABCD_IMPL form, which means they contain the // implementation details for the specific ABCD macro. #define PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y) x##y #define PRIVATE_ACCESS_DETAIL_CONCATENATE(x, y) \ PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y) // @param PtrTypeKind E.g if we have "class A", then it can be "A::*" in case of // members, or it can be "*" in case of statics. #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, \ PtrTypeKind) \ namespace { \ namespace private_access_detail { \ /* Tag type, used to declare different get funcitons for different \ * members \ */ \ struct Tag {}; \ /* Explicit instantiation */ \ template struct private_access; \ /* We can build the PtrType only with two aliases */ \ /* E.g. using PtrType = int(int) *; would be illformed */ \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) = Type; \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) = \ PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) PtrTypeKind; \ /* Declare the friend function, now it is visible in namespace scope. \ * Note, \ * we could declare it inside the Tag type too, in that case ADL would \ * find \ * the declaration. By choosing to declare it here, the Tag type remains \ * a \ * simple tag type, it has no other responsibilities. */ \ PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) get(Tag); \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(Tag, Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*) \ namespace { \ namespace access_private_field { \ Type &Class##Name(Class &&t) { return t.*get(private_access_detail::Tag{}); } \ Type &Class##Name(Class &t) { return t.*get(private_access_detail::Tag{}); } \ /* The following usings are here to avoid duplicate const qualifier \ * warnings \ */ \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag) = Type; \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) = \ const PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag); \ PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) & Class##Name(const Class &t) {\ return t.*get(private_access_detail::Tag{}); \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(Tag, Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*) \ namespace { \ namespace call_private_fun { \ /* We do perfect forwarding, but we want to restrict the overload set \ * only for objects which have the type Class. */ \ template , \ Class>::value> * = nullptr, \ typename... Args> \ auto Class##Name(Obj &&o, Args &&... args) -> decltype( \ (std::forward(o).* \ get(private_access_detail::Tag{}))(std::forward(args)...)) { \ return (std::forward(o).*get(private_access_detail::Tag{}))( \ std::forward(args)...); \ } \ } \ namespace get_private_fun { \ auto Class##Name() -> decltype( \ get(private_access_detail::Tag{})) { \ return (get(private_access_detail::Tag{})); \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD(Tag, Class, Type, \ Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *) \ namespace { \ namespace access_private_static_field { \ namespace Class { \ Type &Class##Name() { return *get(private_access_detail::Tag{}); } \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN(Tag, Class, Type, \ Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *) \ namespace { \ namespace call_private_static_fun { \ namespace Class { \ template \ auto Class##Name(Args &&... args) -> decltype( \ get(private_access_detail::Tag{})(std::forward(args)...)) { \ return get(private_access_detail::Tag{})( \ std::forward(args)...); \ } \ } \ } \ namespace get_private_static_fun { \ namespace Class { \ auto Class##Name() -> decltype(get(private_access_detail::Tag{})) { \ return get(private_access_detail::Tag{}); \ } \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_UNIQUE_TAG \ PRIVATE_ACCESS_DETAIL_CONCATENATE(PrivateAccessTag, __COUNTER__) #define ACCESS_PRIVATE_FIELD(Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, \ Class, Type, Name) #define ACCESS_PRIVATE_FUN(Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, \ Class, Type, Name) #define ACCESS_PRIVATE_STATIC_FIELD(Class, Type, Name) \ Type Class::Name; \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD( \ PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name) #define ACCESS_PRIVATE_STATIC_FUN(Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN( \ PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name) #endif ukui-biometric-auth/tests/kt-test-utils/cpp-stub/addr_any.h0000664000175000017500000002113415167732630022764 0ustar fengfeng#ifndef __ADDR_ANY_H__ #define __ADDR_ANY_H__ //linux #include #include //c #include #include #include //c++ #include #include //project #include "elfio.hpp" class AddrAny { public: AddrAny() { m_init = get_exe_pathname(m_fullname); m_baseaddr = 0; } AddrAny(std::string libname) { m_init = get_lib_pathname_and_baseaddr(libname, m_fullname, m_baseaddr); } int get_local_func_addr_symtab(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_SYMTAB, STB_LOCAL, func_name_regex_str, result); } int get_global_func_addr_symtab(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_SYMTAB, STB_GLOBAL, func_name_regex_str, result); } int get_weak_func_addr_symtab(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_SYMTAB, STB_WEAK, func_name_regex_str, result); } int get_global_func_addr_dynsym( std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_DYNSYM, STB_GLOBAL, func_name_regex_str, result); } int get_weak_func_addr_dynsym(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_DYNSYM, STB_WEAK, func_name_regex_str, result); } private: bool demangle(std::string& s, std::string& name) { int status; char* pname = abi::__cxa_demangle(s.c_str(), 0, 0, &status); if (status != 0) { switch(status) { case -1: name = "memory allocation error"; break; case -2: name = "invalid name given"; break; case -3: name = "internal error: __cxa_demangle: invalid argument"; break; default: name = "unknown error occured"; break; } return false; } name = pname; free(pname); return true; } bool get_exe_pathname( std::string& name) { char line[512]; FILE *fp; uintptr_t base_addr; char perm[5]; unsigned long offset; int pathname_pos; char *pathname; size_t pathname_len; int match = 0; if(NULL == (fp = fopen("/proc/self/maps", "r"))) { return false; } while(fgets(line, sizeof(line), fp)) { if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue; if(0 != offset) continue; //get pathname while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1)) pathname_pos += 1; if(pathname_pos >= (int)(sizeof(line) - 1)) continue; pathname = line + pathname_pos; pathname_len = strlen(pathname); if(0 == pathname_len) continue; if(pathname[pathname_len - 1] == '\n') { pathname[pathname_len - 1] = '\0'; pathname_len -= 1; } if(0 == pathname_len) continue; if('[' == pathname[0]) continue; name = pathname; match = 1; break; } fclose(fp); if(0 == match) { return false; } else { return true; } } bool get_lib_pathname_and_baseaddr(std::string pathname_regex_str, std::string& name, unsigned long& addr) { char line[512]; FILE *fp; uintptr_t base_addr; char perm[5]; unsigned long offset; int pathname_pos; char *pathname; size_t pathname_len; int match; regex_t pathname_regex; regcomp(&pathname_regex, pathname_regex_str.c_str(), 0); if(NULL == (fp = fopen("/proc/self/maps", "r"))) { return false; } while(fgets(line, sizeof(line), fp)) { if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue; //check permission if(perm[0] != 'r') continue; if(perm[3] != 'p') continue; //do not touch the shared memory //check offset // //We are trying to find ELF header in memory. //It can only be found at the beginning of a mapped memory regions //whose offset is 0. if(0 != offset) continue; //get pathname while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1)) pathname_pos += 1; if(pathname_pos >= (int)(sizeof(line) - 1)) continue; pathname = line + pathname_pos; pathname_len = strlen(pathname); if(0 == pathname_len) continue; if(pathname[pathname_len - 1] == '\n') { pathname[pathname_len - 1] = '\0'; pathname_len -= 1; } if(0 == pathname_len) continue; if('[' == pathname[0]) continue; //check pathname //if we need to hook this elf? match = 0; if(0 == regexec(&pathname_regex, pathname, 0, NULL, 0)) { match = 1; name = pathname; addr = (unsigned long)base_addr; break; } if(0 == match) continue; } fclose(fp); if(0 == match) { return false; } else { return true; } } int get_func_addr(unsigned int ttype, unsigned int stype, std::string& func_name_regex_str, std::map& result) { // Create an elfio reader ELFIO::elfio reader; int count = 0; regex_t pathname_regex; if(!m_init) { return -1; } regcomp(&pathname_regex, func_name_regex_str.c_str(), 0); // Load ELF data if(!reader.load(m_fullname.c_str())) { return -1; } ELFIO::Elf_Half sec_num = reader.sections.size(); for(int i = 0; i < sec_num; ++i) { ELFIO::section* psec = reader.sections[i]; // Check section type if(psec->get_type() == ttype) { const ELFIO::symbol_section_accessor symbols( reader, psec ); for ( unsigned int j = 0; j < symbols.get_symbols_num(); ++j ) { std::string name; std::string name_mangle; ELFIO::Elf64_Addr value; ELFIO::Elf_Xword size; unsigned char bind; unsigned char type; ELFIO::Elf_Half section_index; unsigned char other; // Read symbol properties symbols.get_symbol( j, name, value, size, bind, type, section_index, other ); if(type == STT_FUNC && bind == stype) { bool ret = demangle(name,name_mangle); if(ret == true) { if (0 == regexec(&pathname_regex, name_mangle.c_str(), 0, NULL, 0)) { result.insert ( std::pair(name_mangle,(void*)(value + m_baseaddr))); count++; } } else { if (0 == regexec(&pathname_regex, name.c_str(), 0, NULL, 0)) { result.insert ( std::pair(name,(void*)(value + m_baseaddr))); count++; } } } } break; } } return count; } private: bool m_init; std::string m_name; std::string m_fullname; unsigned long m_baseaddr; }; #endif ukui-biometric-auth/tests/kt-test-utils/cpp-stub/elfio.hpp0000664000175000017500000045310415167732630022647 0ustar fengfeng /*** Start of inlined file: elfio_dump.hpp ***/ #ifndef ELFIO_DUMP_HPP #define ELFIO_DUMP_HPP #include #include #include #include #include /*** Start of inlined file: elfio.hpp ***/ #ifndef ELFIO_HPP #define ELFIO_HPP #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4996 ) #pragma warning( disable : 4355 ) #pragma warning( disable : 4244 ) #endif #include #include #include #include #include #include #include #include /*** Start of inlined file: elf_types.hpp ***/ #ifndef ELFTYPES_H #define ELFTYPES_H #ifndef ELFIO_NO_OWN_TYPES #if !defined( ELFIO_NO_CSTDINT ) && !defined( ELFIO_NO_INTTYPES ) #include #else typedef unsigned char uint8_t; typedef signed char int8_t; typedef unsigned short uint16_t; typedef signed short int16_t; #ifdef _MSC_VER typedef unsigned __int32 uint32_t; typedef signed __int32 int32_t; typedef unsigned __int64 uint64_t; typedef signed __int64 int64_t; #else typedef unsigned int uint32_t; typedef signed int int32_t; typedef unsigned long long uint64_t; typedef signed long long int64_t; #endif // _MSC_VER #endif // ELFIO_NO_CSTDINT #endif // ELFIO_NO_OWN_TYPES namespace ELFIO { // Attention! Platform depended definitions. typedef uint16_t Elf_Half; typedef uint32_t Elf_Word; typedef int32_t Elf_Sword; typedef uint64_t Elf_Xword; typedef int64_t Elf_Sxword; typedef uint32_t Elf32_Addr; typedef uint32_t Elf32_Off; typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Off; #define Elf32_Half Elf_Half #define Elf64_Half Elf_Half #define Elf32_Word Elf_Word #define Elf64_Word Elf_Word #define Elf32_Sword Elf_Sword #define Elf64_Sword Elf_Sword /////////////////////// // ELF Header Constants // File type #define ET_NONE 0 #define ET_REL 1 #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 #define ET_LOOS 0xFE00 #define ET_HIOS 0xFEFF #define ET_LOPROC 0xFF00 #define ET_HIPROC 0xFFFF #define EM_NONE 0 // No machine #define EM_M32 1 // AT&T WE 32100 #define EM_SPARC 2 // SUN SPARC #define EM_386 3 // Intel 80386 #define EM_68K 4 // Motorola m68k family #define EM_88K 5 // Motorola m88k family #define EM_486 6 // Intel 80486// Reserved for future use #define EM_860 7 // Intel 80860 #define EM_MIPS 8 // MIPS R3000 (officially, big-endian only) #define EM_S370 9 // IBM System/370 #define EM_MIPS_RS3_LE \ 10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated #define EM_res011 11 // Reserved #define EM_res012 12 // Reserved #define EM_res013 13 // Reserved #define EM_res014 14 // Reserved #define EM_PARISC 15 // HPPA #define EM_res016 16 // Reserved #define EM_VPP550 17 // Fujitsu VPP500 #define EM_SPARC32PLUS 18 // Sun's "v8plus" #define EM_960 19 // Intel 80960 #define EM_PPC 20 // PowerPC #define EM_PPC64 21 // 64-bit PowerPC #define EM_S390 22 // IBM S/390 #define EM_SPU 23 // Sony/Toshiba/IBM SPU #define EM_res024 24 // Reserved #define EM_res025 25 // Reserved #define EM_res026 26 // Reserved #define EM_res027 27 // Reserved #define EM_res028 28 // Reserved #define EM_res029 29 // Reserved #define EM_res030 30 // Reserved #define EM_res031 31 // Reserved #define EM_res032 32 // Reserved #define EM_res033 33 // Reserved #define EM_res034 34 // Reserved #define EM_res035 35 // Reserved #define EM_V800 36 // NEC V800 series #define EM_FR20 37 // Fujitsu FR20 #define EM_RH32 38 // TRW RH32 #define EM_MCORE 39 // Motorola M*Core // May also be taken by Fujitsu MMA #define EM_RCE 39 // Old name for MCore #define EM_ARM 40 // ARM #define EM_OLD_ALPHA 41 // Digital Alpha #define EM_SH 42 // Renesas (formerly Hitachi) / SuperH SH #define EM_SPARCV9 43 // SPARC v9 64-bit #define EM_TRICORE 44 // Siemens Tricore embedded processor #define EM_ARC 45 // ARC Cores #define EM_H8_300 46 // Renesas (formerly Hitachi) H8/300 #define EM_H8_300H 47 // Renesas (formerly Hitachi) H8/300H #define EM_H8S 48 // Renesas (formerly Hitachi) H8S #define EM_H8_500 49 // Renesas (formerly Hitachi) H8/500 #define EM_IA_64 50 // Intel IA-64 Processor #define EM_MIPS_X 51 // Stanford MIPS-X #define EM_COLDFIRE 52 // Motorola Coldfire #define EM_68HC12 53 // Motorola M68HC12 #define EM_MMA 54 // Fujitsu Multimedia Accelerator #define EM_PCP 55 // Siemens PCP #define EM_NCPU 56 // Sony nCPU embedded RISC processor #define EM_NDR1 57 // Denso NDR1 microprocesspr #define EM_STARCORE 58 // Motorola Star*Core processor #define EM_ME16 59 // Toyota ME16 processor #define EM_ST100 60 // STMicroelectronics ST100 processor #define EM_TINYJ 61 // Advanced Logic Corp. TinyJ embedded processor #define EM_X86_64 62 // Advanced Micro Devices X86-64 processor #define EM_PDSP 63 // Sony DSP Processor #define EM_PDP10 64 // Digital Equipment Corp. PDP-10 #define EM_PDP11 65 // Digital Equipment Corp. PDP-11 #define EM_FX66 66 // Siemens FX66 microcontroller #define EM_ST9PLUS 67 // STMicroelectronics ST9+ 8/16 bit microcontroller #define EM_ST7 68 // STMicroelectronics ST7 8-bit microcontroller #define EM_68HC16 69 // Motorola MC68HC16 Microcontroller #define EM_68HC11 70 // Motorola MC68HC11 Microcontroller #define EM_68HC08 71 // Motorola MC68HC08 Microcontroller #define EM_68HC05 72 // Motorola MC68HC05 Microcontroller #define EM_SVX 73 // Silicon Graphics SVx #define EM_ST19 74 // STMicroelectronics ST19 8-bit cpu #define EM_VAX 75 // Digital VAX #define EM_CRIS 76 // Axis Communications 32-bit embedded processor #define EM_JAVELIN 77 // Infineon Technologies 32-bit embedded cpu #define EM_FIREPATH 78 // Element 14 64-bit DSP processor #define EM_ZSP 79 // LSI Logic's 16-bit DSP processor #define EM_MMIX 80 // Donald Knuth's educational 64-bit processor #define EM_HUANY 81 // Harvard's machine-independent format #define EM_PRISM 82 // SiTera Prism #define EM_AVR 83 // Atmel AVR 8-bit microcontroller #define EM_FR30 84 // Fujitsu FR30 #define EM_D10V 85 // Mitsubishi D10V #define EM_D30V 86 // Mitsubishi D30V #define EM_V850 87 // NEC v850 #define EM_M32R 88 // Renesas M32R (formerly Mitsubishi M32R) #define EM_MN10300 89 // Matsushita MN10300 #define EM_MN10200 90 // Matsushita MN10200 #define EM_PJ 91 // picoJava #define EM_OPENRISC 92 // OpenRISC 32-bit embedded processor #define EM_ARC_A5 93 // ARC Cores Tangent-A5 #define EM_XTENSA 94 // Tensilica Xtensa Architecture #define EM_VIDEOCORE 95 // Alphamosaic VideoCore processor #define EM_TMM_GPP 96 // Thompson Multimedia General Purpose Processor #define EM_NS32K 97 // National Semiconductor 32000 series #define EM_TPC 98 // Tenor Network TPC processor #define EM_SNP1K 99 // Trebia SNP 1000 processor #define EM_ST200 100 // STMicroelectronics ST200 microcontroller #define EM_IP2K 101 // Ubicom IP2022 micro controller #define EM_MAX 102 // MAX Processor #define EM_CR 103 // National Semiconductor CompactRISC #define EM_F2MC16 104 // Fujitsu F2MC16 #define EM_MSP430 105 // TI msp430 micro controller #define EM_BLACKFIN 106 // ADI Blackfin #define EM_SE_C33 107 // S1C33 Family of Seiko Epson processors #define EM_SEP 108 // Sharp embedded microprocessor #define EM_ARCA 109 // Arca RISC Microprocessor #define EM_UNICORE \ 110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University #define EM_EXCESS 111 // eXcess: 16/32/64-bit configurable embedded CPU #define EM_DXP 112 // Icera Semiconductor Inc. Deep Execution Processor #define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor #define EM_CRX 114 // National Semiconductor CRX #define EM_XGATE 115 // Motorola XGATE embedded processor #define EM_C166 116 // Infineon C16x/XC16x processor #define EM_M16C 117 // Renesas M16C series microprocessors #define EM_DSPIC30F \ 118 // Microchip Technology dsPIC30F Digital Signal Controller #define EM_CE 119 // Freescale Communication Engine RISC core #define EM_M32C 120 // Renesas M32C series microprocessors #define EM_res121 121 // Reserved #define EM_res122 122 // Reserved #define EM_res123 123 // Reserved #define EM_res124 124 // Reserved #define EM_res125 125 // Reserved #define EM_res126 126 // Reserved #define EM_res127 127 // Reserved #define EM_res128 128 // Reserved #define EM_res129 129 // Reserved #define EM_res130 130 // Reserved #define EM_TSK3000 131 // Altium TSK3000 core #define EM_RS08 132 // Freescale RS08 embedded processor #define EM_res133 133 // Reserved #define EM_ECOG2 134 // Cyan Technology eCOG2 microprocessor #define EM_SCORE 135 // Sunplus Score #define EM_SCORE7 135 // Sunplus S+core7 RISC processor #define EM_DSP24 136 // New Japan Radio (NJR) 24-bit DSP Processor #define EM_VIDEOCORE3 137 // Broadcom VideoCore III processor #define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture #define EM_SE_C17 139 // Seiko Epson C17 family #define EM_TI_C6000 140 // Texas Instruments TMS320C6000 DSP family #define EM_TI_C2000 141 // Texas Instruments TMS320C2000 DSP family #define EM_TI_C5500 142 // Texas Instruments TMS320C55x DSP family #define EM_res143 143 // Reserved #define EM_res144 144 // Reserved #define EM_res145 145 // Reserved #define EM_res146 146 // Reserved #define EM_res147 147 // Reserved #define EM_res148 148 // Reserved #define EM_res149 149 // Reserved #define EM_res150 150 // Reserved #define EM_res151 151 // Reserved #define EM_res152 152 // Reserved #define EM_res153 153 // Reserved #define EM_res154 154 // Reserved #define EM_res155 155 // Reserved #define EM_res156 156 // Reserved #define EM_res157 157 // Reserved #define EM_res158 158 // Reserved #define EM_res159 159 // Reserved #define EM_MMDSP_PLUS 160 // STMicroelectronics 64bit VLIW Data Signal Processor #define EM_CYPRESS_M8C 161 // Cypress M8C microprocessor #define EM_R32C 162 // Renesas R32C series microprocessors #define EM_TRIMEDIA 163 // NXP Semiconductors TriMedia architecture family #define EM_QDSP6 164 // QUALCOMM DSP6 Processor #define EM_8051 165 // Intel 8051 and variants #define EM_STXP7X 166 // STMicroelectronics STxP7x family #define EM_NDS32 \ 167 // Andes Technology compact code size embedded RISC processor family #define EM_ECOG1 168 // Cyan Technology eCOG1X family #define EM_ECOG1X 168 // Cyan Technology eCOG1X family #define EM_MAXQ30 169 // Dallas Semiconductor MAXQ30 Core Micro-controllers #define EM_XIMO16 170 // New Japan Radio (NJR) 16-bit DSP Processor #define EM_MANIK 171 // M2000 Reconfigurable RISC Microprocessor #define EM_CRAYNV2 172 // Cray Inc. NV2 vector architecture #define EM_RX 173 // Renesas RX family #define EM_METAG 174 // Imagination Technologies META processor architecture #define EM_MCST_ELBRUS 175 // MCST Elbrus general purpose hardware architecture #define EM_ECOG16 176 // Cyan Technology eCOG16 family #define EM_CR16 177 // National Semiconductor CompactRISC 16-bit processor #define EM_ETPU 178 // Freescale Extended Time Processing Unit #define EM_SLE9X 179 // Infineon Technologies SLE9X core #define EM_L1OM 180 // Intel L1OM #define EM_INTEL181 181 // Reserved by Intel #define EM_INTEL182 182 // Reserved by Intel #define EM_res183 183 // Reserved by ARM #define EM_res184 184 // Reserved by ARM #define EM_AVR32 185 // Atmel Corporation 32-bit microprocessor family #define EM_STM8 186 // STMicroeletronics STM8 8-bit microcontroller #define EM_TILE64 187 // Tilera TILE64 multicore architecture family #define EM_TILEPRO 188 // Tilera TILEPro multicore architecture family #define EM_MICROBLAZE 189 // Xilinx MicroBlaze 32-bit RISC soft processor core #define EM_CUDA 190 // NVIDIA CUDA architecture #define EM_TILEGX 191 // Tilera TILE-Gx multicore architecture family #define EM_CLOUDSHIELD 192 // CloudShield architecture family #define EM_COREA_1ST 193 // KIPO-KAIST Core-A 1st generation processor family #define EM_COREA_2ND 194 // KIPO-KAIST Core-A 2nd generation processor family #define EM_ARC_COMPACT2 195 // Synopsys ARCompact V2 #define EM_OPEN8 196 // Open8 8-bit RISC soft processor core #define EM_RL78 197 // Renesas RL78 family #define EM_VIDEOCORE5 198 // Broadcom VideoCore V processor #define EM_78KOR 199 // Renesas 78KOR family #define EM_56800EX 200 // Freescale 56800EX Digital Signal Controller (DSC) #define EM_BA1 201 // Beyond BA1 CPU architecture #define EM_BA2 202 // Beyond BA2 CPU architecture #define EM_XCORE 203 // XMOS xCORE processor family #define EM_MCHP_PIC 204 // Microchip 8-bit PIC(r) family #define EM_INTEL205 205 // Reserved by Intel #define EM_INTEL206 206 // Reserved by Intel #define EM_INTEL207 207 // Reserved by Intel #define EM_INTEL208 208 // Reserved by Intel #define EM_INTEL209 209 // Reserved by Intel #define EM_KM32 210 // KM211 KM32 32-bit processor #define EM_KMX32 211 // KM211 KMX32 32-bit processor #define EM_KMX16 212 // KM211 KMX16 16-bit processor #define EM_KMX8 213 // KM211 KMX8 8-bit processor #define EM_KVARC 214 // KM211 KVARC processor #define EM_CDP 215 // Paneve CDP architecture family #define EM_COGE 216 // Cognitive Smart Memory Processor #define EM_COOL 217 // iCelero CoolEngine #define EM_NORC 218 // Nanoradio Optimized RISC #define EM_CSR_KALIMBA 219 // CSR Kalimba architecture family #define EM_Z80 220 // Zilog Z80 #define EM_VISIUM 221 // Controls and Data Services VISIUMcore processor #define EM_FT32 222 // FTDI Chip FT32 high performance 32-bit RISC architecture #define EM_MOXIE 223 // Moxie processor family #define EM_AMDGPU 224 // AMD GPU architecture #define EM_RISCV 243 // RISC-V #define EM_LANAI 244 // Lanai processor #define EM_CEVA 245 // CEVA Processor Architecture Family #define EM_CEVA_X2 246 // CEVA X2 Processor Family #define EM_BPF 247 // Linux BPF – in-kernel virtual machine #define EM_GRAPHCORE_IPU 248 // Graphcore Intelligent Processing Unit #define EM_IMG1 249 // Imagination Technologies #define EM_NFP 250 // Netronome Flow Processor (P) #define EM_CSKY 252 // C-SKY processor family // File version #define EV_NONE 0 #define EV_CURRENT 1 // Identification index #define EI_MAG0 0 #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_OSABI 7 #define EI_ABIVERSION 8 #define EI_PAD 9 #define EI_NIDENT 16 // Magic number #define ELFMAG0 0x7F #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' // File class #define ELFCLASSNONE 0 #define ELFCLASS32 1 #define ELFCLASS64 2 // Encoding #define ELFDATANONE 0 #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 // OS extensions #define ELFOSABI_NONE 0 // No extensions or unspecified #define ELFOSABI_HPUX 1 // Hewlett-Packard HP-UX #define ELFOSABI_NETBSD 2 // NetBSD #define ELFOSABI_LINUX 3 // Linux #define ELFOSABI_SOLARIS 6 // Sun Solaris #define ELFOSABI_AIX 7 // AIX #define ELFOSABI_IRIX 8 // IRIX #define ELFOSABI_FREEBSD 9 // FreeBSD #define ELFOSABI_TRU64 10 // Compaq TRU64 UNIX #define ELFOSABI_MODESTO 11 // Novell Modesto #define ELFOSABI_OPENBSD 12 // Open BSD #define ELFOSABI_OPENVMS 13 // Open VMS #define ELFOSABI_NSK 14 // Hewlett-Packard Non-Stop Kernel #define ELFOSABI_AROS 15 // Amiga Research OS #define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS // 64-255 Architecture-specific value range #define ELFOSABI_AMDGPU_HSA \ 64 // AMDGPU OS for HSA compatible compute // kernels. #define ELFOSABI_AMDGPU_PAL \ 65 // AMDGPU OS for AMD PAL compatible graphics // shaders and compute kernels. #define ELFOSABI_AMDGPU_MESA3D \ 66 // AMDGPU OS for Mesa3D compatible graphics // shaders and compute kernels. // AMDGPU specific e_flags #define EF_AMDGPU_MACH 0x0ff // AMDGPU processor selection mask. #define EF_AMDGPU_XNACK \ 0x100 // Indicates if the XNACK target feature is // enabled for all code contained in the ELF. // AMDGPU processors #define EF_AMDGPU_MACH_NONE 0x000 // Unspecified processor. #define EF_AMDGPU_MACH_R600_R600 0x001 #define EF_AMDGPU_MACH_R600_R630 0x002 #define EF_AMDGPU_MACH_R600_RS880 0x003 #define EF_AMDGPU_MACH_R600_RV670 0x004 #define EF_AMDGPU_MACH_R600_RV710 0x005 #define EF_AMDGPU_MACH_R600_RV730 0x006 #define EF_AMDGPU_MACH_R600_RV770 0x007 #define EF_AMDGPU_MACH_R600_CEDAR 0x008 #define EF_AMDGPU_MACH_R600_CYPRESS 0x009 #define EF_AMDGPU_MACH_R600_JUNIPER 0x00a #define EF_AMDGPU_MACH_R600_REDWOOD 0x00b #define EF_AMDGPU_MACH_R600_SUMO 0x00c #define EF_AMDGPU_MACH_R600_BARTS 0x00d #define EF_AMDGPU_MACH_R600_CAICOS 0x00e #define EF_AMDGPU_MACH_R600_CAYMAN 0x00f #define EF_AMDGPU_MACH_R600_TURKS 0x010 #define EF_AMDGPU_MACH_R600_RESERVED_FIRST 0x011 #define EF_AMDGPU_MACH_R600_RESERVED_LAST 0x01f #define EF_AMDGPU_MACH_R600_FIRST EF_AMDGPU_MACH_R600_R600 #define EF_AMDGPU_MACH_R600_LAST EF_AMDGPU_MACH_R600_TURKS #define EF_AMDGPU_MACH_AMDGCN_GFX600 0x020 #define EF_AMDGPU_MACH_AMDGCN_GFX601 0x021 #define EF_AMDGPU_MACH_AMDGCN_GFX700 0x022 #define EF_AMDGPU_MACH_AMDGCN_GFX701 0x023 #define EF_AMDGPU_MACH_AMDGCN_GFX702 0x024 #define EF_AMDGPU_MACH_AMDGCN_GFX703 0x025 #define EF_AMDGPU_MACH_AMDGCN_GFX704 0x026 #define EF_AMDGPU_MACH_AMDGCN_GFX801 0x028 #define EF_AMDGPU_MACH_AMDGCN_GFX802 0x029 #define EF_AMDGPU_MACH_AMDGCN_GFX803 0x02a #define EF_AMDGPU_MACH_AMDGCN_GFX810 0x02b #define EF_AMDGPU_MACH_AMDGCN_GFX900 0x02c #define EF_AMDGPU_MACH_AMDGCN_GFX902 0x02d #define EF_AMDGPU_MACH_AMDGCN_GFX904 0x02e #define EF_AMDGPU_MACH_AMDGCN_GFX906 0x02f #define EF_AMDGPU_MACH_AMDGCN_RESERVED0 0x027 #define EF_AMDGPU_MACH_AMDGCN_RESERVED1 0x030 #define EF_AMDGPU_MACH_AMDGCN_FIRST EF_AMDGPU_MACH_AMDGCN_GFX600 #define EF_AMDGPU_MACH_AMDGCN_LAST EF_AMDGPU_MACH_AMDGCN_GFX906 ///////////////////// // Sections constants // Section indexes #define SHN_UNDEF 0 #define SHN_LORESERVE 0xFF00 #define SHN_LOPROC 0xFF00 #define SHN_HIPROC 0xFF1F #define SHN_LOOS 0xFF20 #define SHN_HIOS 0xFF3F #define SHN_ABS 0xFFF1 #define SHN_COMMON 0xFFF2 #define SHN_XINDEX 0xFFFF #define SHN_HIRESERVE 0xFFFF // Section types #define SHT_NULL 0 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 #define SHT_STRTAB 3 #define SHT_RELA 4 #define SHT_HASH 5 #define SHT_DYNAMIC 6 #define SHT_NOTE 7 #define SHT_NOBITS 8 #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 #define SHT_INIT_ARRAY 14 #define SHT_FINI_ARRAY 15 #define SHT_PREINIT_ARRAY 16 #define SHT_GROUP 17 #define SHT_SYMTAB_SHNDX 18 #define SHT_LOOS 0x60000000 #define SHT_HIOS 0x6fffffff #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7FFFFFFF #define SHT_LOUSER 0x80000000 #define SHT_HIUSER 0xFFFFFFFF // Section attribute flags #define SHF_WRITE 0x1 #define SHF_ALLOC 0x2 #define SHF_EXECINSTR 0x4 #define SHF_MERGE 0x10 #define SHF_STRINGS 0x20 #define SHF_INFO_LINK 0x40 #define SHF_LINK_ORDER 0x80 #define SHF_OS_NONCONFORMING 0x100 #define SHF_GROUP 0x200 #define SHF_TLS 0x400 #define SHF_MASKOS 0x0ff00000 #define SHF_MASKPROC 0xF0000000 // Section group flags #define GRP_COMDAT 0x1 #define GRP_MASKOS 0x0ff00000 #define GRP_MASKPROC 0xf0000000 // Symbol binding #define STB_LOCAL 0 #define STB_GLOBAL 1 #define STB_WEAK 2 #define STB_LOOS 10 #define STB_HIOS 12 #define STB_MULTIDEF 13 #define STB_LOPROC 13 #define STB_HIPROC 15 // Note types #define NT_AMDGPU_METADATA 1 #define NT_AMD_AMDGPU_HSA_METADATA 10 #define NT_AMD_AMDGPU_ISA 11 #define NT_AMD_AMDGPU_PAL_METADATA 12 // Symbol types #define STT_NOTYPE 0 #define STT_OBJECT 1 #define STT_FUNC 2 #define STT_SECTION 3 #define STT_FILE 4 #define STT_COMMON 5 #define STT_TLS 6 #define STT_LOOS 10 #define STT_AMDGPU_HSA_KERNEL 10 #define STT_HIOS 12 #define STT_LOPROC 13 #define STT_HIPROC 15 // Symbol visibility #define STV_DEFAULT 0 #define STV_INTERNAL 1 #define STV_HIDDEN 2 #define STV_PROTECTED 3 // Undefined name #define STN_UNDEF 0 // Relocation types #define R_386_NONE 0 #define R_X86_64_NONE 0 #define R_AMDGPU_NONE 0 #define R_386_32 1 #define R_X86_64_64 1 #define R_AMDGPU_ABS32_LO 1 #define R_386_PC32 2 #define R_X86_64_PC32 2 #define R_AMDGPU_ABS32_HI 2 #define R_386_GOT32 3 #define R_X86_64_GOT32 3 #define R_AMDGPU_ABS64 3 #define R_386_PLT32 4 #define R_X86_64_PLT32 4 #define R_AMDGPU_REL32 4 #define R_386_COPY 5 #define R_X86_64_COPY 5 #define R_AMDGPU_REL64 5 #define R_386_GLOB_DAT 6 #define R_X86_64_GLOB_DAT 6 #define R_AMDGPU_ABS32 6 #define R_386_JMP_SLOT 7 #define R_X86_64_JUMP_SLOT 7 #define R_AMDGPU_GOTPCREL 7 #define R_386_RELATIVE 8 #define R_X86_64_RELATIVE 8 #define R_AMDGPU_GOTPCREL32_LO 8 #define R_386_GOTOFF 9 #define R_X86_64_GOTPCREL 9 #define R_AMDGPU_GOTPCREL32_HI 9 #define R_386_GOTPC 10 #define R_X86_64_32 10 #define R_AMDGPU_REL32_LO 10 #define R_386_32PLT 11 #define R_X86_64_32S 11 #define R_AMDGPU_REL32_HI 11 #define R_X86_64_16 12 #define R_X86_64_PC16 13 #define R_AMDGPU_RELATIVE64 13 #define R_386_TLS_TPOFF 14 #define R_X86_64_8 14 #define R_386_TLS_IE 15 #define R_X86_64_PC8 15 #define R_386_TLS_GOTIE 16 #define R_X86_64_DTPMOD64 16 #define R_386_TLS_LE 17 #define R_X86_64_DTPOFF64 17 #define R_386_TLS_GD 18 #define R_X86_64_TPOFF64 18 #define R_386_TLS_LDM 19 #define R_X86_64_TLSGD 19 #define R_386_16 20 #define R_X86_64_TLSLD 20 #define R_386_PC16 21 #define R_X86_64_DTPOFF32 21 #define R_386_8 22 #define R_X86_64_GOTTPOFF 22 #define R_386_PC8 23 #define R_X86_64_TPOFF32 23 #define R_386_TLS_GD_32 24 #define R_X86_64_PC64 24 #define R_386_TLS_GD_PUSH 25 #define R_X86_64_GOTOFF64 25 #define R_386_TLS_GD_CALL 26 #define R_X86_64_GOTPC32 26 #define R_386_TLS_GD_POP 27 #define R_X86_64_GOT64 27 #define R_386_TLS_LDM_32 28 #define R_X86_64_GOTPCREL64 28 #define R_386_TLS_LDM_PUSH 29 #define R_X86_64_GOTPC64 29 #define R_386_TLS_LDM_CALL 30 #define R_X86_64_GOTPLT64 30 #define R_386_TLS_LDM_POP 31 #define R_X86_64_PLTOFF64 31 #define R_386_TLS_LDO_32 32 #define R_386_TLS_IE_32 33 #define R_386_TLS_LE_32 34 #define R_X86_64_GOTPC32_TLSDESC 34 #define R_386_TLS_DTPMOD32 35 #define R_X86_64_TLSDESC_CALL 35 #define R_386_TLS_DTPOFF32 36 #define R_X86_64_TLSDESC 36 #define R_386_TLS_TPOFF32 37 #define R_X86_64_IRELATIVE 37 #define R_386_SIZE32 38 #define R_386_TLS_GOTDESC 39 #define R_386_TLS_DESC_CALL 40 #define R_386_TLS_DESC 41 #define R_386_IRELATIVE 42 #define R_386_GOT32X 43 #define R_X86_64_GNU_VTINHERIT 250 #define R_X86_64_GNU_VTENTRY 251 // Segment types #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_TLS 7 #define PT_LOOS 0x60000000 #define PT_HIOS 0x6fffffff #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7FFFFFFF // Segment flags #define PF_X 1 // Execute #define PF_W 2 // Write #define PF_R 4 // Read #define PF_MASKOS 0x0ff00000 // Unspecified #define PF_MASKPROC 0xf0000000 // Unspecified // Dynamic Array Tags #define DT_NULL 0 #define DT_NEEDED 1 #define DT_PLTRELSZ 2 #define DT_PLTGOT 3 #define DT_HASH 4 #define DT_STRTAB 5 #define DT_SYMTAB 6 #define DT_RELA 7 #define DT_RELASZ 8 #define DT_RELAENT 9 #define DT_STRSZ 10 #define DT_SYMENT 11 #define DT_INIT 12 #define DT_FINI 13 #define DT_SONAME 14 #define DT_RPATH 15 #define DT_SYMBOLIC 16 #define DT_REL 17 #define DT_RELSZ 18 #define DT_RELENT 19 #define DT_PLTREL 20 #define DT_DEBUG 21 #define DT_TEXTREL 22 #define DT_JMPREL 23 #define DT_BIND_NOW 24 #define DT_INIT_ARRAY 25 #define DT_FINI_ARRAY 26 #define DT_INIT_ARRAYSZ 27 #define DT_FINI_ARRAYSZ 28 #define DT_RUNPATH 29 #define DT_FLAGS 30 #define DT_ENCODING 32 #define DT_PREINIT_ARRAY 32 #define DT_PREINIT_ARRAYSZ 33 #define DT_MAXPOSTAGS 34 #define DT_LOOS 0x6000000D #define DT_HIOS 0x6ffff000 #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7FFFFFFF // DT_FLAGS values #define DF_ORIGIN 0x1 #define DF_SYMBOLIC 0x2 #define DF_TEXTREL 0x4 #define DF_BIND_NOW 0x8 #define DF_STATIC_TLS 0x10 // ELF file header struct Elf32_Ehdr { unsigned char e_ident[EI_NIDENT]; Elf_Half e_type; Elf_Half e_machine; Elf_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf_Word e_flags; Elf_Half e_ehsize; Elf_Half e_phentsize; Elf_Half e_phnum; Elf_Half e_shentsize; Elf_Half e_shnum; Elf_Half e_shstrndx; }; struct Elf64_Ehdr { unsigned char e_ident[EI_NIDENT]; Elf_Half e_type; Elf_Half e_machine; Elf_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf_Word e_flags; Elf_Half e_ehsize; Elf_Half e_phentsize; Elf_Half e_phnum; Elf_Half e_shentsize; Elf_Half e_shnum; Elf_Half e_shstrndx; }; // Section header struct Elf32_Shdr { Elf_Word sh_name; Elf_Word sh_type; Elf_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf_Word sh_size; Elf_Word sh_link; Elf_Word sh_info; Elf_Word sh_addralign; Elf_Word sh_entsize; }; struct Elf64_Shdr { Elf_Word sh_name; Elf_Word sh_type; Elf_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf_Xword sh_size; Elf_Word sh_link; Elf_Word sh_info; Elf_Xword sh_addralign; Elf_Xword sh_entsize; }; // Segment header struct Elf32_Phdr { Elf_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf_Word p_filesz; Elf_Word p_memsz; Elf_Word p_flags; Elf_Word p_align; }; struct Elf64_Phdr { Elf_Word p_type; Elf_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf_Xword p_filesz; Elf_Xword p_memsz; Elf_Xword p_align; }; // Symbol table entry struct Elf32_Sym { Elf_Word st_name; Elf32_Addr st_value; Elf_Word st_size; unsigned char st_info; unsigned char st_other; Elf_Half st_shndx; }; struct Elf64_Sym { Elf_Word st_name; unsigned char st_info; unsigned char st_other; Elf_Half st_shndx; Elf64_Addr st_value; Elf_Xword st_size; }; #define ELF_ST_BIND( i ) ( ( i ) >> 4 ) #define ELF_ST_TYPE( i ) ( (i)&0xf ) #define ELF_ST_INFO( b, t ) ( ( ( b ) << 4 ) + ( (t)&0xf ) ) #define ELF_ST_VISIBILITY( o ) ( (o)&0x3 ) // Relocation entries struct Elf32_Rel { Elf32_Addr r_offset; Elf_Word r_info; }; struct Elf32_Rela { Elf32_Addr r_offset; Elf_Word r_info; Elf_Sword r_addend; }; struct Elf64_Rel { Elf64_Addr r_offset; Elf_Xword r_info; }; struct Elf64_Rela { Elf64_Addr r_offset; Elf_Xword r_info; Elf_Sxword r_addend; }; #define ELF32_R_SYM( i ) ( ( i ) >> 8 ) #define ELF32_R_TYPE( i ) ( (unsigned char)( i ) ) #define ELF32_R_INFO( s, t ) ( ( ( s ) << 8 ) + (unsigned char)( t ) ) #define ELF64_R_SYM( i ) ( ( i ) >> 32 ) #define ELF64_R_TYPE( i ) ( (i)&0xffffffffL ) #define ELF64_R_INFO( s, t ) \ ( ( ( ( int64_t )( s ) ) << 32 ) + ( (t)&0xffffffffL ) ) // Dynamic structure struct Elf32_Dyn { Elf_Sword d_tag; union { Elf_Word d_val; Elf32_Addr d_ptr; } d_un; }; struct Elf64_Dyn { Elf_Sxword d_tag; union { Elf_Xword d_val; Elf64_Addr d_ptr; } d_un; }; } // namespace ELFIO #endif // ELFTYPES_H /*** End of inlined file: elf_types.hpp ***/ /*** Start of inlined file: elfio_version.hpp ***/ #define ELFIO_VERSION "3.8" /*** End of inlined file: elfio_version.hpp ***/ /*** Start of inlined file: elfio_utils.hpp ***/ #ifndef ELFIO_UTILS_HPP #define ELFIO_UTILS_HPP #define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ TYPE get_##NAME() const { return ( *convertor )( FIELD ); } #define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ void set_##NAME( TYPE value ) \ { \ FIELD = value; \ FIELD = ( *convertor )( FIELD ); \ } #define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ TYPE get_##NAME() const { return ( *convertor )( FIELD ); } \ void set_##NAME( TYPE value ) \ { \ FIELD = value; \ FIELD = ( *convertor )( FIELD ); \ } #define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 #define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ virtual void set_##NAME( TYPE value ) = 0 #define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ virtual TYPE get_##NAME() const = 0; \ virtual void set_##NAME( TYPE value ) = 0 namespace ELFIO { //------------------------------------------------------------------------------ class endianess_convertor { public: //------------------------------------------------------------------------------ endianess_convertor() { need_conversion = false; } //------------------------------------------------------------------------------ void setup( unsigned char elf_file_encoding ) { need_conversion = ( elf_file_encoding != get_host_encoding() ); } //------------------------------------------------------------------------------ uint64_t operator()( uint64_t value ) const { if ( !need_conversion ) { return value; } value = ( ( value & 0x00000000000000FFull ) << 56 ) | ( ( value & 0x000000000000FF00ull ) << 40 ) | ( ( value & 0x0000000000FF0000ull ) << 24 ) | ( ( value & 0x00000000FF000000ull ) << 8 ) | ( ( value & 0x000000FF00000000ull ) >> 8 ) | ( ( value & 0x0000FF0000000000ull ) >> 24 ) | ( ( value & 0x00FF000000000000ull ) >> 40 ) | ( ( value & 0xFF00000000000000ull ) >> 56 ); return value; } //------------------------------------------------------------------------------ int64_t operator()( int64_t value ) const { if ( !need_conversion ) { return value; } return ( int64_t )( *this )( (uint64_t)value ); } //------------------------------------------------------------------------------ uint32_t operator()( uint32_t value ) const { if ( !need_conversion ) { return value; } value = ( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) | ( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 ); return value; } //------------------------------------------------------------------------------ int32_t operator()( int32_t value ) const { if ( !need_conversion ) { return value; } return ( int32_t )( *this )( (uint32_t)value ); } //------------------------------------------------------------------------------ uint16_t operator()( uint16_t value ) const { if ( !need_conversion ) { return value; } value = ( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 ); return value; } //------------------------------------------------------------------------------ int16_t operator()( int16_t value ) const { if ( !need_conversion ) { return value; } return ( int16_t )( *this )( (uint16_t)value ); } //------------------------------------------------------------------------------ int8_t operator()( int8_t value ) const { return value; } //------------------------------------------------------------------------------ uint8_t operator()( uint8_t value ) const { return value; } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ unsigned char get_host_encoding() const { static const int tmp = 1; if ( 1 == *(const char*)&tmp ) { return ELFDATA2LSB; } else { return ELFDATA2MSB; } } //------------------------------------------------------------------------------ private: bool need_conversion; }; //------------------------------------------------------------------------------ inline uint32_t elf_hash( const unsigned char* name ) { uint32_t h = 0, g; while ( *name ) { h = ( h << 4 ) + *name++; g = h & 0xf0000000; if ( g != 0 ) h ^= g >> 24; h &= ~g; } return h; } } // namespace ELFIO #endif // ELFIO_UTILS_HPP /*** End of inlined file: elfio_utils.hpp ***/ /*** Start of inlined file: elfio_header.hpp ***/ #ifndef ELF_HEADER_HPP #define ELF_HEADER_HPP #include namespace ELFIO { class elf_header { public: virtual ~elf_header(){}; virtual bool load( std::istream& stream ) = 0; virtual bool save( std::ostream& stream ) const = 0; // ELF header functions ELFIO_GET_ACCESS_DECL( unsigned char, class ); ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); }; template struct elf_header_impl_types; template <> struct elf_header_impl_types { typedef Elf32_Phdr Phdr_type; typedef Elf32_Shdr Shdr_type; static const unsigned char file_class = ELFCLASS32; }; template <> struct elf_header_impl_types { typedef Elf64_Phdr Phdr_type; typedef Elf64_Shdr Shdr_type; static const unsigned char file_class = ELFCLASS64; }; template class elf_header_impl : public elf_header { public: //------------------------------------------------------------------------------ elf_header_impl( endianess_convertor* convertor_, unsigned char encoding ) { convertor = convertor_; std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); header.e_ident[EI_MAG0] = ELFMAG0; header.e_ident[EI_MAG1] = ELFMAG1; header.e_ident[EI_MAG2] = ELFMAG2; header.e_ident[EI_MAG3] = ELFMAG3; header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; header.e_ident[EI_DATA] = encoding; header.e_ident[EI_VERSION] = EV_CURRENT; header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT ); header.e_ehsize = ( sizeof( header ) ); header.e_ehsize = ( *convertor )( header.e_ehsize ); header.e_shstrndx = ( *convertor )( (Elf_Half)1 ); header.e_phentsize = sizeof( typename elf_header_impl_types::Phdr_type ); header.e_shentsize = sizeof( typename elf_header_impl_types::Shdr_type ); header.e_phentsize = ( *convertor )( header.e_phentsize ); header.e_shentsize = ( *convertor )( header.e_shentsize ); } //------------------------------------------------------------------------------ bool load( std::istream& stream ) { stream.seekg( 0 ); stream.read( reinterpret_cast( &header ), sizeof( header ) ); return ( stream.gcount() == sizeof( header ) ); } //------------------------------------------------------------------------------ bool save( std::ostream& stream ) const { stream.seekp( 0 ); stream.write( reinterpret_cast( &header ), sizeof( header ) ); return stream.good(); } //------------------------------------------------------------------------------ // ELF header functions ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version ); ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); ELFIO_GET_SET_ACCESS( unsigned char, abi_version, header.e_ident[EI_ABIVERSION] ); ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); private: T header; endianess_convertor* convertor; }; } // namespace ELFIO #endif // ELF_HEADER_HPP /*** End of inlined file: elfio_header.hpp ***/ /*** Start of inlined file: elfio_section.hpp ***/ #ifndef ELFIO_SECTION_HPP #define ELFIO_SECTION_HPP #include #include #include namespace ELFIO { class section { friend class elfio; public: virtual ~section(){}; ELFIO_GET_ACCESS_DECL( Elf_Half, index ); ELFIO_GET_SET_ACCESS_DECL( std::string, name ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); virtual const char* get_data() const = 0; virtual void set_data( const char* pData, Elf_Word size ) = 0; virtual void set_data( const std::string& data ) = 0; virtual void append_data( const char* pData, Elf_Word size ) = 0; virtual void append_data( const std::string& data ) = 0; virtual size_t get_stream_size() const = 0; virtual void set_stream_size( size_t value ) = 0; protected: ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); ELFIO_SET_ACCESS_DECL( Elf_Half, index ); virtual void load( std::istream& stream, std::streampos header_offset ) = 0; virtual void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) = 0; virtual bool is_address_initialized() const = 0; }; template class section_impl : public section { public: //------------------------------------------------------------------------------ section_impl( const endianess_convertor* convertor_ ) : convertor( convertor_ ) { std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); is_address_set = false; data = 0; data_size = 0; index = 0; stream_size = 0; } //------------------------------------------------------------------------------ ~section_impl() { delete[] data; } //------------------------------------------------------------------------------ // Section info functions ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr ); //------------------------------------------------------------------------------ Elf_Half get_index() const { return index; } //------------------------------------------------------------------------------ std::string get_name() const { return name; } //------------------------------------------------------------------------------ void set_name( std::string name_ ) { name = name_; } //------------------------------------------------------------------------------ void set_address( Elf64_Addr value ) { header.sh_addr = value; header.sh_addr = ( *convertor )( header.sh_addr ); is_address_set = true; } //------------------------------------------------------------------------------ bool is_address_initialized() const { return is_address_set; } //------------------------------------------------------------------------------ const char* get_data() const { return data; } //------------------------------------------------------------------------------ void set_data( const char* raw_data, Elf_Word size ) { if ( get_type() != SHT_NOBITS ) { delete[] data; data = new ( std::nothrow ) char[size]; if ( 0 != data && 0 != raw_data ) { data_size = size; std::copy( raw_data, raw_data + size, data ); } else { data_size = 0; } } set_size( data_size ); } //------------------------------------------------------------------------------ void set_data( const std::string& str_data ) { return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); } //------------------------------------------------------------------------------ void append_data( const char* raw_data, Elf_Word size ) { if ( get_type() != SHT_NOBITS ) { if ( get_size() + size < data_size ) { std::copy( raw_data, raw_data + size, data + get_size() ); } else { data_size = 2 * ( data_size + size ); char* new_data = new ( std::nothrow ) char[data_size]; if ( 0 != new_data ) { std::copy( data, data + get_size(), new_data ); std::copy( raw_data, raw_data + size, new_data + get_size() ); delete[] data; data = new_data; } else { size = 0; } } set_size( get_size() + size ); } } //------------------------------------------------------------------------------ void append_data( const std::string& str_data ) { return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); } //------------------------------------------------------------------------------ protected: //------------------------------------------------------------------------------ ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); //------------------------------------------------------------------------------ void set_index( Elf_Half value ) { index = value; } //------------------------------------------------------------------------------ void load( std::istream& stream, std::streampos header_offset ) { std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); stream.seekg( 0, stream.end ); set_stream_size( stream.tellg() ); stream.seekg( header_offset ); stream.read( reinterpret_cast( &header ), sizeof( header ) ); Elf_Xword size = get_size(); if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() && size < get_stream_size() ) { data = new ( std::nothrow ) char[size + 1]; if ( ( 0 != size ) && ( 0 != data ) ) { stream.seekg( ( *convertor )( header.sh_offset ) ); stream.read( data, size ); data[size] = 0; // Ensure data is ended with 0 to avoid oob read data_size = size; } else { data_size = 0; } } } //------------------------------------------------------------------------------ void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) { if ( 0 != get_index() ) { header.sh_offset = data_offset; header.sh_offset = ( *convertor )( header.sh_offset ); } save_header( stream, header_offset ); if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && get_size() != 0 && data != 0 ) { save_data( stream, data_offset ); } } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ void save_header( std::ostream& stream, std::streampos header_offset ) const { stream.seekp( header_offset ); stream.write( reinterpret_cast( &header ), sizeof( header ) ); } //------------------------------------------------------------------------------ void save_data( std::ostream& stream, std::streampos data_offset ) const { stream.seekp( data_offset ); stream.write( get_data(), get_size() ); } //------------------------------------------------------------------------------ size_t get_stream_size() const { return stream_size; } //------------------------------------------------------------------------------ void set_stream_size( size_t value ) { stream_size = value; } //------------------------------------------------------------------------------ private: T header; Elf_Half index; std::string name; char* data; Elf_Word data_size; const endianess_convertor* convertor; bool is_address_set; size_t stream_size; }; } // namespace ELFIO #endif // ELFIO_SECTION_HPP /*** End of inlined file: elfio_section.hpp ***/ /*** Start of inlined file: elfio_segment.hpp ***/ #ifndef ELFIO_SEGMENT_HPP #define ELFIO_SEGMENT_HPP #include #include #include namespace ELFIO { class segment { friend class elfio; public: virtual ~segment(){}; ELFIO_GET_ACCESS_DECL( Elf_Half, index ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); virtual const char* get_data() const = 0; virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0; virtual Elf_Half get_sections_num() const = 0; virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; virtual bool is_offset_initialized() const = 0; protected: ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); ELFIO_SET_ACCESS_DECL( Elf_Half, index ); virtual const std::vector& get_sections() const = 0; virtual void load( std::istream& stream, std::streampos header_offset ) = 0; virtual void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) = 0; }; //------------------------------------------------------------------------------ template class segment_impl : public segment { public: //------------------------------------------------------------------------------ segment_impl( endianess_convertor* convertor_ ) : stream_size( 0 ), index( 0 ), data( 0 ), convertor( convertor_ ) { is_offset_set = false; std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); } //------------------------------------------------------------------------------ virtual ~segment_impl() { delete[] data; } //------------------------------------------------------------------------------ // Section info functions ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); size_t stream_size; //------------------------------------------------------------------------------ size_t get_stream_size() const { return stream_size; } //------------------------------------------------------------------------------ void set_stream_size( size_t value ) { stream_size = value; } //------------------------------------------------------------------------------ Elf_Half get_index() const { return index; } //------------------------------------------------------------------------------ const char* get_data() const { return data; } //------------------------------------------------------------------------------ Elf_Half add_section_index( Elf_Half sec_index, Elf_Xword addr_align ) { sections.push_back( sec_index ); if ( addr_align > get_align() ) { set_align( addr_align ); } return (Elf_Half)sections.size(); } //------------------------------------------------------------------------------ Elf_Half get_sections_num() const { return (Elf_Half)sections.size(); } //------------------------------------------------------------------------------ Elf_Half get_section_index_at( Elf_Half num ) const { if ( num < sections.size() ) { return sections[num]; } return Elf_Half( -1 ); } //------------------------------------------------------------------------------ protected: //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void set_offset( Elf64_Off value ) { ph.p_offset = value; ph.p_offset = ( *convertor )( ph.p_offset ); is_offset_set = true; } //------------------------------------------------------------------------------ bool is_offset_initialized() const { return is_offset_set; } //------------------------------------------------------------------------------ const std::vector& get_sections() const { return sections; } //------------------------------------------------------------------------------ void set_index( Elf_Half value ) { index = value; } //------------------------------------------------------------------------------ void load( std::istream& stream, std::streampos header_offset ) { stream.seekg( 0, stream.end ); set_stream_size( stream.tellg() ); stream.seekg( header_offset ); stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); is_offset_set = true; if ( PT_NULL != get_type() && 0 != get_file_size() ) { stream.seekg( ( *convertor )( ph.p_offset ) ); Elf_Xword size = get_file_size(); if ( size > get_stream_size() ) { data = 0; } else { data = new (std::nothrow) char[size + 1]; if ( 0 != data ) { stream.read( data, size ); data[size] = 0; } } } } //------------------------------------------------------------------------------ void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) { ph.p_offset = data_offset; ph.p_offset = ( *convertor )( ph.p_offset ); stream.seekp( header_offset ); stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); } //------------------------------------------------------------------------------ private: T ph; Elf_Half index; char* data; std::vector sections; endianess_convertor* convertor; bool is_offset_set; }; } // namespace ELFIO #endif // ELFIO_SEGMENT_HPP /*** End of inlined file: elfio_segment.hpp ***/ /*** Start of inlined file: elfio_strings.hpp ***/ #ifndef ELFIO_STRINGS_HPP #define ELFIO_STRINGS_HPP #include #include #include namespace ELFIO { //------------------------------------------------------------------------------ template class string_section_accessor_template { public: //------------------------------------------------------------------------------ string_section_accessor_template( S* section_ ) : string_section( section_ ) { } //------------------------------------------------------------------------------ const char* get_string( Elf_Word index ) const { if ( string_section ) { if ( index < string_section->get_size() ) { const char* data = string_section->get_data(); if ( 0 != data ) { return data + index; } } } return 0; } //------------------------------------------------------------------------------ Elf_Word add_string( const char* str ) { Elf_Word current_position = 0; if ( string_section ) { // Strings are addeded to the end of the current section data current_position = (Elf_Word)string_section->get_size(); if ( current_position == 0 ) { char empty_string = '\0'; string_section->append_data( &empty_string, 1 ); current_position++; } string_section->append_data( str, (Elf_Word)std::strlen( str ) + 1 ); } return current_position; } //------------------------------------------------------------------------------ Elf_Word add_string( const std::string& str ) { return add_string( str.c_str() ); } //------------------------------------------------------------------------------ private: S* string_section; }; using string_section_accessor = string_section_accessor_template

; using const_string_section_accessor = string_section_accessor_template; } // namespace ELFIO #endif // ELFIO_STRINGS_HPP /*** End of inlined file: elfio_strings.hpp ***/ #define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; } #define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ TYPE get_##FNAME() const \ { \ return header ? ( header->get_##FNAME() ) : 0; \ } \ void set_##FNAME( TYPE val ) \ { \ if ( header ) { \ header->set_##FNAME( val ); \ } \ } namespace ELFIO { //------------------------------------------------------------------------------ class elfio { public: //------------------------------------------------------------------------------ elfio() : sections( this ), segments( this ) { header = 0; current_file_pos = 0; create( ELFCLASS32, ELFDATA2LSB ); } //------------------------------------------------------------------------------ ~elfio() { clean(); } //------------------------------------------------------------------------------ void create( unsigned char file_class, unsigned char encoding ) { clean(); convertor.setup( encoding ); header = create_header( file_class, encoding ); create_mandatory_sections(); } //------------------------------------------------------------------------------ bool load( const std::string& file_name ) { std::ifstream stream; stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); if ( !stream ) { return false; } return load( stream ); } //------------------------------------------------------------------------------ bool load( std::istream& stream ) { clean(); unsigned char e_ident[EI_NIDENT]; // Read ELF file signature stream.read( reinterpret_cast( &e_ident ), sizeof( e_ident ) ); // Is it ELF file? if ( stream.gcount() != sizeof( e_ident ) || e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { return false; } if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && ( e_ident[EI_CLASS] != ELFCLASS32 ) ) { return false; } convertor.setup( e_ident[EI_DATA] ); header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); if ( 0 == header ) { return false; } if ( !header->load( stream ) ) { return false; } load_sections( stream ); bool is_still_good = load_segments( stream ); return is_still_good; } //------------------------------------------------------------------------------ bool save( const std::string& file_name ) { std::ofstream stream; stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); if ( !stream ) { return false; } return save( stream ); } //------------------------------------------------------------------------------ bool save( std::ostream& stream ) { if ( !stream || !header ) { return false; } bool is_still_good = true; // Define layout specific header fields // The position of the segment table is fixed after the header. // The position of the section table is variable and needs to be fixed // before saving. header->set_segments_num( segments.size() ); header->set_segments_offset( segments.size() ? header->get_header_size() : 0 ); header->set_sections_num( sections.size() ); header->set_sections_offset( 0 ); // Layout the first section right after the segment table current_file_pos = header->get_header_size() + header->get_segment_entry_size() * (Elf_Xword)header->get_segments_num(); calc_segment_alignment(); is_still_good = layout_segments_and_their_sections(); is_still_good = is_still_good && layout_sections_without_segments(); is_still_good = is_still_good && layout_section_table(); is_still_good = is_still_good && save_header( stream ); is_still_good = is_still_good && save_sections( stream ); is_still_good = is_still_good && save_segments( stream ); return is_still_good; } //------------------------------------------------------------------------------ // ELF header access functions ELFIO_HEADER_ACCESS_GET( unsigned char, class ); ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); //------------------------------------------------------------------------------ const endianess_convertor& get_convertor() const { return convertor; } //------------------------------------------------------------------------------ Elf_Xword get_default_entry_size( Elf_Word section_type ) const { switch ( section_type ) { case SHT_RELA: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Rela ); } else { return sizeof( Elf32_Rela ); } case SHT_REL: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Rel ); } else { return sizeof( Elf32_Rel ); } case SHT_SYMTAB: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Sym ); } else { return sizeof( Elf32_Sym ); } case SHT_DYNAMIC: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Dyn ); } else { return sizeof( Elf32_Dyn ); } default: return 0; } } //------------------------------------------------------------------------------ private: bool is_offset_in_section( Elf64_Off offset, const section* sec ) const { return ( offset >= sec->get_offset() ) && ( offset < ( sec->get_offset() + sec->get_size() ) ); } //------------------------------------------------------------------------------ public: //! returns an empty string if no problems are detected, //! or a string containing an error message if problems are found std::string validate() const { // check for overlapping sections in the file for ( int i = 0; i < sections.size(); ++i ) { for ( int j = i + 1; j < sections.size(); ++j ) { const section* a = sections[i]; const section* b = sections[j]; if ( !( a->get_type() & SHT_NOBITS ) && !( b->get_type() & SHT_NOBITS ) && ( a->get_size() > 0 ) && ( b->get_size() > 0 ) && ( a->get_offset() > 0 ) && ( b->get_offset() > 0 ) ) { if ( is_offset_in_section( a->get_offset(), b ) || is_offset_in_section( a->get_offset() + a->get_size() - 1, b ) || is_offset_in_section( b->get_offset(), a ) || is_offset_in_section( b->get_offset() + b->get_size() - 1, a ) ) { return "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file"; } } } } // more checks to be added here... return ""; } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ void clean() { delete header; header = 0; std::vector::const_iterator it; for ( it = sections_.begin(); it != sections_.end(); ++it ) { delete *it; } sections_.clear(); std::vector::const_iterator it1; for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) { delete *it1; } segments_.clear(); } //------------------------------------------------------------------------------ elf_header* create_header( unsigned char file_class, unsigned char encoding ) { elf_header* new_header = 0; if ( file_class == ELFCLASS64 ) { new_header = new elf_header_impl( &convertor, encoding ); } else if ( file_class == ELFCLASS32 ) { new_header = new elf_header_impl( &convertor, encoding ); } else { return 0; } return new_header; } //------------------------------------------------------------------------------ section* create_section() { section* new_section; unsigned char file_class = get_class(); if ( file_class == ELFCLASS64 ) { new_section = new section_impl( &convertor ); } else if ( file_class == ELFCLASS32 ) { new_section = new section_impl( &convertor ); } else { return 0; } new_section->set_index( (Elf_Half)sections_.size() ); sections_.push_back( new_section ); return new_section; } //------------------------------------------------------------------------------ segment* create_segment() { segment* new_segment; unsigned char file_class = header->get_class(); if ( file_class == ELFCLASS64 ) { new_segment = new segment_impl( &convertor ); } else if ( file_class == ELFCLASS32 ) { new_segment = new segment_impl( &convertor ); } else { return 0; } new_segment->set_index( (Elf_Half)segments_.size() ); segments_.push_back( new_segment ); return new_segment; } //------------------------------------------------------------------------------ void create_mandatory_sections() { // Create null section without calling to 'add_section' as no string // section containing section names exists yet section* sec0 = create_section(); sec0->set_index( 0 ); sec0->set_name( "" ); sec0->set_name_string_offset( 0 ); set_section_name_str_index( 1 ); section* shstrtab = sections.add( ".shstrtab" ); shstrtab->set_type( SHT_STRTAB ); shstrtab->set_addr_align( 1 ); } //------------------------------------------------------------------------------ Elf_Half load_sections( std::istream& stream ) { Elf_Half entry_size = header->get_section_entry_size(); Elf_Half num = header->get_sections_num(); Elf64_Off offset = header->get_sections_offset(); for ( Elf_Half i = 0; i < num; ++i ) { section* sec = create_section(); sec->load( stream, (std::streamoff)offset + (std::streampos)i * entry_size ); sec->set_index( i ); // To mark that the section is not permitted to reassign address // during layout calculation sec->set_address( sec->get_address() ); } Elf_Half shstrndx = get_section_name_str_index(); if ( SHN_UNDEF != shstrndx ) { string_section_accessor str_reader( sections[shstrndx] ); for ( Elf_Half i = 0; i < num; ++i ) { Elf_Word section_offset = sections[i]->get_name_string_offset(); const char* p = str_reader.get_string( section_offset ); if ( p != 0 ) { sections[i]->set_name( p ); } } } return num; } //------------------------------------------------------------------------------ //! Checks whether the addresses of the section entirely fall within the given segment. //! It doesn't matter if the addresses are memory addresses, or file offsets, //! they just need to be in the same address space bool is_sect_in_seg( Elf64_Off sect_begin, Elf_Xword sect_size, Elf64_Off seg_begin, Elf64_Off seg_end ) { return ( seg_begin <= sect_begin ) && ( sect_begin + sect_size <= seg_end ) && ( sect_begin < seg_end ); // this is important criteria when sect_size == 0 // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) // sect_begin=12, sect_size=0 -> shall return false! } //------------------------------------------------------------------------------ bool load_segments( std::istream& stream ) { Elf_Half entry_size = header->get_segment_entry_size(); Elf_Half num = header->get_segments_num(); Elf64_Off offset = header->get_segments_offset(); for ( Elf_Half i = 0; i < num; ++i ) { segment* seg; unsigned char file_class = header->get_class(); if ( file_class == ELFCLASS64 ) { seg = new segment_impl( &convertor ); } else if ( file_class == ELFCLASS32 ) { seg = new segment_impl( &convertor ); } else { return false; } seg->load( stream, (std::streamoff)offset + (std::streampos)i * entry_size ); seg->set_index( i ); // Add sections to the segments (similar to readelfs algorithm) Elf64_Off segBaseOffset = seg->get_offset(); Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); Elf64_Off segVBaseAddr = seg->get_virtual_address(); Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); for ( Elf_Half j = 0; j < sections.size(); ++j ) { const section* psec = sections[j]; // SHF_ALLOC sections are matched based on the virtual address // otherwise the file offset is matched if ( ( psec->get_flags() & SHF_ALLOC ) ? is_sect_in_seg( psec->get_address(), psec->get_size(), segVBaseAddr, segVEndAddr ) : is_sect_in_seg( psec->get_offset(), psec->get_size(), segBaseOffset, segEndOffset ) ) { // Alignment of segment shall not be updated, to preserve original value // It will be re-calculated on saving. seg->add_section_index( psec->get_index(), 0 ); } } // Add section into the segments' container segments_.push_back( seg ); } return true; } //------------------------------------------------------------------------------ bool save_header( std::ostream& stream ) { return header->save( stream ); } //------------------------------------------------------------------------------ bool save_sections( std::ostream& stream ) { for ( unsigned int i = 0; i < sections_.size(); ++i ) { section* sec = sections_.at( i ); std::streampos headerPosition = (std::streamoff)header->get_sections_offset() + (std::streampos)header->get_section_entry_size() * sec->get_index(); sec->save( stream, headerPosition, sec->get_offset() ); } return true; } //------------------------------------------------------------------------------ bool save_segments( std::ostream& stream ) { for ( unsigned int i = 0; i < segments_.size(); ++i ) { segment* seg = segments_.at( i ); std::streampos headerPosition = header->get_segments_offset() + (std::streampos)header->get_segment_entry_size() * seg->get_index(); seg->save( stream, headerPosition, seg->get_offset() ); } return true; } //------------------------------------------------------------------------------ bool is_section_without_segment( unsigned int section_index ) { bool found = false; for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { for ( unsigned int k = 0; !found && ( k < segments[j]->get_sections_num() ); ++k ) { found = segments[j]->get_section_index_at( k ) == section_index; } } return !found; } //------------------------------------------------------------------------------ bool is_subsequence_of( segment* seg1, segment* seg2 ) { // Return 'true' if sections of seg1 are a subset of sections in seg2 const std::vector& sections1 = seg1->get_sections(); const std::vector& sections2 = seg2->get_sections(); bool found = false; if ( sections1.size() < sections2.size() ) { found = std::includes( sections2.begin(), sections2.end(), sections1.begin(), sections1.end() ); } return found; } //------------------------------------------------------------------------------ std::vector get_ordered_segments() { std::vector res; std::deque worklist; res.reserve( segments.size() ); std::copy( segments_.begin(), segments_.end(), std::back_inserter( worklist ) ); // Bring the segments which start at address 0 to the front size_t nextSlot = 0; for ( size_t i = 0; i < worklist.size(); ++i ) { if ( i != nextSlot && worklist[i]->is_offset_initialized() && worklist[i]->get_offset() == 0 ) { if ( worklist[nextSlot]->get_offset() == 0 ) { ++nextSlot; } std::swap( worklist[i], worklist[nextSlot] ); ++nextSlot; } } while ( !worklist.empty() ) { segment* seg = worklist.front(); worklist.pop_front(); size_t i = 0; for ( ; i < worklist.size(); ++i ) { if ( is_subsequence_of( seg, worklist[i] ) ) { break; } } if ( i < worklist.size() ) worklist.push_back( seg ); else res.push_back( seg ); } return res; } //------------------------------------------------------------------------------ bool layout_sections_without_segments() { for ( unsigned int i = 0; i < sections_.size(); ++i ) { if ( is_section_without_segment( i ) ) { section* sec = sections_[i]; Elf_Xword section_align = sec->get_addr_align(); if ( section_align > 1 && current_file_pos % section_align != 0 ) { current_file_pos += section_align - current_file_pos % section_align; } if ( 0 != sec->get_index() ) sec->set_offset( current_file_pos ); if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) { current_file_pos += sec->get_size(); } } } return true; } //------------------------------------------------------------------------------ void calc_segment_alignment() { for ( std::vector::iterator s = segments_.begin(); s != segments_.end(); ++s ) { segment* seg = *s; for ( int i = 0; i < seg->get_sections_num(); ++i ) { section* sect = sections_[seg->get_section_index_at( i )]; if ( sect->get_addr_align() > seg->get_align() ) { seg->set_align( sect->get_addr_align() ); } } } } //------------------------------------------------------------------------------ bool layout_segments_and_their_sections() { std::vector worklist; std::vector section_generated( sections.size(), false ); // Get segments in a order in where segments which contain a // sub sequence of other segments are located at the end worklist = get_ordered_segments(); for ( unsigned int i = 0; i < worklist.size(); ++i ) { Elf_Xword segment_memory = 0; Elf_Xword segment_filesize = 0; Elf_Xword seg_start_pos = current_file_pos; segment* seg = worklist[i]; // Special case: PHDR segment // This segment contains the program headers but no sections if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { seg_start_pos = header->get_segments_offset(); segment_memory = segment_filesize = header->get_segment_entry_size() * (Elf_Xword)header->get_segments_num(); } // Special case: else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { seg_start_pos = 0; if ( seg->get_sections_num() ) { segment_memory = segment_filesize = current_file_pos; } } // New segments with not generated sections // have to be aligned else if ( seg->get_sections_num() && !section_generated[seg->get_section_index_at( 0 )] ) { Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; Elf64_Off cur_page_alignment = current_file_pos % align; Elf64_Off req_page_alignment = seg->get_virtual_address() % align; Elf64_Off error = req_page_alignment - cur_page_alignment; current_file_pos += ( seg->get_align() + error ) % align; seg_start_pos = current_file_pos; } else if ( seg->get_sections_num() ) { seg_start_pos = sections[seg->get_section_index_at( 0 )]->get_offset(); } // Write segment's data for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) { Elf_Half index = seg->get_section_index_at( j ); section* sec = sections[index]; // The NULL section is always generated if ( SHT_NULL == sec->get_type() ) { section_generated[index] = true; continue; } Elf_Xword secAlign = 0; // Fix up the alignment if ( !section_generated[index] && sec->is_address_initialized() && SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && 0 != sec->get_size() ) { // Align the sections based on the virtual addresses // when possible (this is what matters for execution) Elf64_Off req_offset = sec->get_address() - seg->get_virtual_address(); Elf64_Off cur_offset = current_file_pos - seg_start_pos; if ( req_offset < cur_offset ) { // something has gone awfully wrong, abort! // secAlign would turn out negative, seeking backwards and overwriting previous data return false; } secAlign = req_offset - cur_offset; } else if ( !section_generated[index] && !sec->is_address_initialized() ) { // If no address has been specified then only the section // alignment constraint has to be matched Elf_Xword align = sec->get_addr_align(); if ( align == 0 ) { align = 1; } Elf64_Off error = current_file_pos % align; secAlign = ( align - error ) % align; } else if ( section_generated[index] ) { // Alignment for already generated sections secAlign = sec->get_offset() - seg_start_pos - segment_filesize; } // Determine the segment file and memory sizes // Special case .tbss section (NOBITS) in non TLS segment if ( ( sec->get_flags() & SHF_ALLOC ) && !( ( sec->get_flags() & SHF_TLS ) && ( seg->get_type() != PT_TLS ) && ( SHT_NOBITS == sec->get_type() ) ) ) segment_memory += sec->get_size() + secAlign; if ( SHT_NOBITS != sec->get_type() ) segment_filesize += sec->get_size() + secAlign; // Nothing to be done when generating nested segments if ( section_generated[index] ) { continue; } current_file_pos += secAlign; // Set the section addresses when missing if ( !sec->is_address_initialized() ) sec->set_address( seg->get_virtual_address() + current_file_pos - seg_start_pos ); if ( 0 != sec->get_index() ) sec->set_offset( current_file_pos ); if ( SHT_NOBITS != sec->get_type() ) current_file_pos += sec->get_size(); section_generated[index] = true; } seg->set_file_size( segment_filesize ); // If we already have a memory size from loading an elf file (value > 0), // it must not shrink! // Memory size may be bigger than file size and it is the loader's job to do something // with the surplus bytes in memory, like initializing them with a defined value. if ( seg->get_memory_size() < segment_memory ) { seg->set_memory_size( segment_memory ); } seg->set_offset( seg_start_pos ); } return true; } //------------------------------------------------------------------------------ bool layout_section_table() { // Simply place the section table at the end for now Elf64_Off alignmentError = current_file_pos % 4; current_file_pos += ( 4 - alignmentError ) % 4; header->set_sections_offset( current_file_pos ); return true; } //------------------------------------------------------------------------------ public: friend class Sections; class Sections { public: //------------------------------------------------------------------------------ Sections( elfio* parent_ ) : parent( parent_ ) {} //------------------------------------------------------------------------------ Elf_Half size() const { return (Elf_Half)parent->sections_.size(); } //------------------------------------------------------------------------------ section* operator[]( unsigned int index ) const { section* sec = 0; if ( index < parent->sections_.size() ) { sec = parent->sections_[index]; } return sec; } //------------------------------------------------------------------------------ section* operator[]( const std::string& name ) const { section* sec = 0; std::vector::const_iterator it; for ( it = parent->sections_.begin(); it != parent->sections_.end(); ++it ) { if ( ( *it )->get_name() == name ) { sec = *it; break; } } return sec; } //------------------------------------------------------------------------------ section* add( const std::string& name ) { section* new_section = parent->create_section(); new_section->set_name( name ); Elf_Half str_index = parent->get_section_name_str_index(); section* string_table( parent->sections_[str_index] ); string_section_accessor str_writer( string_table ); Elf_Word pos = str_writer.add_string( name ); new_section->set_name_string_offset( pos ); return new_section; } //------------------------------------------------------------------------------ std::vector::iterator begin() { return parent->sections_.begin(); } //------------------------------------------------------------------------------ std::vector::iterator end() { return parent->sections_.end(); } //------------------------------------------------------------------------------ std::vector::const_iterator begin() const { return parent->sections_.cbegin(); } //------------------------------------------------------------------------------ std::vector::const_iterator end() const { return parent->sections_.cend(); } //------------------------------------------------------------------------------ private: elfio* parent; } sections; //------------------------------------------------------------------------------ public: friend class Segments; class Segments { public: //------------------------------------------------------------------------------ Segments( elfio* parent_ ) : parent( parent_ ) {} //------------------------------------------------------------------------------ Elf_Half size() const { return (Elf_Half)parent->segments_.size(); } //------------------------------------------------------------------------------ segment* operator[]( unsigned int index ) const { return parent->segments_[index]; } //------------------------------------------------------------------------------ segment* add() { return parent->create_segment(); } //------------------------------------------------------------------------------ std::vector::iterator begin() { return parent->segments_.begin(); } //------------------------------------------------------------------------------ std::vector::iterator end() { return parent->segments_.end(); } //------------------------------------------------------------------------------ std::vector::const_iterator begin() const { return parent->segments_.cbegin(); } //------------------------------------------------------------------------------ std::vector::const_iterator end() const { return parent->segments_.cend(); } //------------------------------------------------------------------------------ private: elfio* parent; } segments; //------------------------------------------------------------------------------ private: elf_header* header; std::vector sections_; std::vector segments_; endianess_convertor convertor; Elf_Xword current_file_pos; }; } // namespace ELFIO /*** Start of inlined file: elfio_symbols.hpp ***/ #ifndef ELFIO_SYMBOLS_HPP #define ELFIO_SYMBOLS_HPP namespace ELFIO { //------------------------------------------------------------------------------ template class symbol_section_accessor_template { public: //------------------------------------------------------------------------------ symbol_section_accessor_template( const elfio& elf_file_, S* symbol_section_ ) : elf_file( elf_file_ ), symbol_section( symbol_section_ ) { find_hash_section(); } //------------------------------------------------------------------------------ Elf_Xword get_symbols_num() const { Elf_Xword nRet = 0; if ( 0 != symbol_section->get_entry_size() ) { nRet = symbol_section->get_size() / symbol_section->get_entry_size(); } return nRet; } //------------------------------------------------------------------------------ bool get_symbol( Elf_Xword index, std::string& name, Elf64_Addr& value, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { bool ret = false; if ( elf_file.get_class() == ELFCLASS32 ) { ret = generic_get_symbol( index, name, value, size, bind, type, section_index, other ); } else { ret = generic_get_symbol( index, name, value, size, bind, type, section_index, other ); } return ret; } //------------------------------------------------------------------------------ bool get_symbol( const std::string& name, Elf64_Addr& value, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { bool ret = false; if ( 0 != get_hash_table_index() ) { Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); Elf_Word nchain = *(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); Elf_Word y = *(const Elf_Word*)( hash_section->get_data() + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); std::string str; get_symbol( y, str, value, size, bind, type, section_index, other ); while ( str != name && STN_UNDEF != y && y < nchain ) { y = *(const Elf_Word*)( hash_section->get_data() + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); get_symbol( y, str, value, size, bind, type, section_index, other ); } if ( str == name ) { ret = true; } } else { for ( Elf_Xword i = 0; i < get_symbols_num() && !ret; i++ ) { std::string symbol_name; if ( get_symbol( i, symbol_name, value, size, bind, type, section_index, other ) ) { if ( symbol_name == name ) { ret = true; } } } } return ret; } //------------------------------------------------------------------------------ bool get_symbol( const Elf64_Addr& value, std::string& name, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { const endianess_convertor& convertor = elf_file.get_convertor(); Elf_Xword idx = 0; bool match = false; Elf64_Addr v = 0; if ( elf_file.get_class() == ELFCLASS32 ) { match = generic_search_symbols( [&]( const Elf32_Sym* sym ) { return convertor( sym->st_value ) == value; }, idx ); } else { match = generic_search_symbols( [&]( const Elf64_Sym* sym ) { return convertor( sym->st_value ) == value; }, idx ); } if ( match ) { return get_symbol( idx, name, v, size, bind, type, section_index, other ); } return false; } //------------------------------------------------------------------------------ Elf_Word add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, unsigned char info, unsigned char other, Elf_Half shndx ) { Elf_Word nRet; if ( symbol_section->get_size() == 0 ) { if ( elf_file.get_class() == ELFCLASS32 ) { nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); } else { nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); } } if ( elf_file.get_class() == ELFCLASS32 ) { nRet = generic_add_symbol( name, value, size, info, other, shndx ); } else { nRet = generic_add_symbol( name, value, size, info, other, shndx ); } return nRet; } //------------------------------------------------------------------------------ Elf_Word add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, unsigned char bind, unsigned char type, unsigned char other, Elf_Half shndx ) { return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, shndx ); } //------------------------------------------------------------------------------ Elf_Word add_symbol( string_section_accessor& pStrWriter, const char* str, Elf64_Addr value, Elf_Xword size, unsigned char info, unsigned char other, Elf_Half shndx ) { Elf_Word index = pStrWriter.add_string( str ); return add_symbol( index, value, size, info, other, shndx ); } //------------------------------------------------------------------------------ Elf_Word add_symbol( string_section_accessor& pStrWriter, const char* str, Elf64_Addr value, Elf_Xword size, unsigned char bind, unsigned char type, unsigned char other, Elf_Half shndx ) { return add_symbol( pStrWriter, str, value, size, ELF_ST_INFO( bind, type ), other, shndx ); } //------------------------------------------------------------------------------ Elf_Xword arrange_local_symbols( std::function func = nullptr ) { int nRet = 0; if ( elf_file.get_class() == ELFCLASS32 ) { nRet = generic_arrange_local_symbols( func ); } else { nRet = generic_arrange_local_symbols( func ); } return nRet; } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ void find_hash_section() { hash_section = 0; hash_section_index = 0; Elf_Half nSecNo = elf_file.sections.size(); for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) { const section* sec = elf_file.sections[i]; if ( sec->get_link() == symbol_section->get_index() ) { hash_section = sec; hash_section_index = i; } } } //------------------------------------------------------------------------------ Elf_Half get_string_table_index() const { return (Elf_Half)symbol_section->get_link(); } //------------------------------------------------------------------------------ Elf_Half get_hash_table_index() const { return hash_section_index; } //------------------------------------------------------------------------------ template const T* generic_get_symbol_ptr( Elf_Xword index ) const { if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { const T* pSym = reinterpret_cast( symbol_section->get_data() + index * symbol_section->get_entry_size() ); return pSym; } return nullptr; } //------------------------------------------------------------------------------ template bool generic_search_symbols( std::function match, Elf_Xword& idx ) const { for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { const T* symPtr = generic_get_symbol_ptr( i ); if ( symPtr == nullptr ) return false; if ( match( symPtr ) ) { idx = i; return true; } } return false; } //------------------------------------------------------------------------------ template bool generic_get_symbol( Elf_Xword index, std::string& name, Elf64_Addr& value, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { bool ret = false; if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { const T* pSym = reinterpret_cast( symbol_section->get_data() + index * symbol_section->get_entry_size() ); const endianess_convertor& convertor = elf_file.get_convertor(); section* string_section = elf_file.sections[get_string_table_index()]; string_section_accessor str_reader( string_section ); const char* pStr = str_reader.get_string( convertor( pSym->st_name ) ); if ( 0 != pStr ) { name = pStr; } value = convertor( pSym->st_value ); size = convertor( pSym->st_size ); bind = ELF_ST_BIND( pSym->st_info ); type = ELF_ST_TYPE( pSym->st_info ); section_index = convertor( pSym->st_shndx ); other = pSym->st_other; ret = true; } return ret; } //------------------------------------------------------------------------------ template Elf_Word generic_add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, unsigned char info, unsigned char other, Elf_Half shndx ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; entry.st_name = convertor( name ); entry.st_value = value; entry.st_value = convertor( entry.st_value ); entry.st_size = size; entry.st_size = convertor( entry.st_size ); entry.st_info = convertor( info ); entry.st_other = convertor( other ); entry.st_shndx = convertor( shndx ); symbol_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1; return nRet; } //------------------------------------------------------------------------------ template Elf_Xword generic_arrange_local_symbols( std::function func ) { const endianess_convertor& convertor = elf_file.get_convertor(); const Elf_Xword size = symbol_section->get_entry_size(); Elf_Xword first_not_local = 1; // Skip the first entry. It is always NOTYPE Elf_Xword current = 0; Elf_Xword count = get_symbols_num(); while ( true ) { T* p1 = nullptr; T* p2 = nullptr; while ( first_not_local < count ) { p1 = const_cast( generic_get_symbol_ptr( first_not_local ) ); if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL ) break; ++first_not_local; } current = first_not_local + 1; while ( current < count ) { p2 = const_cast( generic_get_symbol_ptr( current ) ); if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL ) break; ++current; } if ( first_not_local < count && current < count ) { if ( func ) func( first_not_local, current ); // Swap the symbols T tmp; std::copy( p1, p1 + 1, &tmp ); std::copy( p2, p2 + 1, p1 ); std::copy( &tmp, &tmp + 1, p2 ); } else { // Update 'info' field of the section symbol_section->set_info( first_not_local ); break; } } // Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1; return first_not_local; } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* symbol_section; Elf_Half hash_section_index; const section* hash_section; }; using symbol_section_accessor = symbol_section_accessor_template
; using const_symbol_section_accessor = symbol_section_accessor_template; } // namespace ELFIO #endif // ELFIO_SYMBOLS_HPP /*** End of inlined file: elfio_symbols.hpp ***/ /*** Start of inlined file: elfio_note.hpp ***/ #ifndef ELFIO_NOTE_HPP #define ELFIO_NOTE_HPP namespace ELFIO { //------------------------------------------------------------------------------ // There are discrepancies in documentations. SCO documentation // (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) // requires 8 byte entries alignment for 64-bit ELF file, // but Oracle's definition uses the same structure // for 32-bit and 64-bit formats. // (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) // // It looks like EM_X86_64 Linux implementation is similar to Oracle's // definition. Therefore, the same alignment works for both formats //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ template class note_section_accessor_template { public: //------------------------------------------------------------------------------ note_section_accessor_template( const elfio& elf_file_, S* section_ ) : elf_file( elf_file_ ), note_section( section_ ) { process_section(); } //------------------------------------------------------------------------------ Elf_Word get_notes_num() const { return (Elf_Word)note_start_positions.size(); } //------------------------------------------------------------------------------ bool get_note( Elf_Word index, Elf_Word& type, std::string& name, void*& desc, Elf_Word& descSize ) const { if ( index >= note_section->get_size() ) { return false; } const char* pData = note_section->get_data() + note_start_positions[index]; int align = sizeof( Elf_Word ); const endianess_convertor& convertor = elf_file.get_convertor(); type = convertor( *(const Elf_Word*)( pData + 2 * align ) ); Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); Elf_Xword max_name_size = note_section->get_size() - note_start_positions[index]; if ( namesz < 1 || namesz > max_name_size || (Elf_Xword)namesz + descSize > max_name_size ) { return false; } name.assign( pData + 3 * align, namesz - 1 ); if ( 0 == descSize ) { desc = 0; } else { desc = const_cast( pData + 3 * align + ( ( namesz + align - 1 ) / align ) * align ); } return true; } //------------------------------------------------------------------------------ void add_note( Elf_Word type, const std::string& name, const void* desc, Elf_Word descSize ) { const endianess_convertor& convertor = elf_file.get_convertor(); int align = sizeof( Elf_Word ); Elf_Word nameLen = (Elf_Word)name.size() + 1; Elf_Word nameLenConv = convertor( nameLen ); std::string buffer( reinterpret_cast( &nameLenConv ), align ); Elf_Word descSizeConv = convertor( descSize ); buffer.append( reinterpret_cast( &descSizeConv ), align ); type = convertor( type ); buffer.append( reinterpret_cast( &type ), align ); buffer.append( name ); buffer.append( 1, '\x00' ); const char pad[] = { '\0', '\0', '\0', '\0' }; if ( nameLen % align != 0 ) { buffer.append( pad, align - nameLen % align ); } if ( desc != 0 && descSize != 0 ) { buffer.append( reinterpret_cast( desc ), descSize ); if ( descSize % align != 0 ) { buffer.append( pad, align - descSize % align ); } } note_start_positions.push_back( note_section->get_size() ); note_section->append_data( buffer ); } private: //------------------------------------------------------------------------------ void process_section() { const endianess_convertor& convertor = elf_file.get_convertor(); const char* data = note_section->get_data(); Elf_Xword size = note_section->get_size(); Elf_Xword current = 0; note_start_positions.clear(); // Is it empty? if ( 0 == data || 0 == size ) { return; } Elf_Word align = sizeof( Elf_Word ); while ( current + (Elf_Xword)3 * align <= size ) { note_start_positions.push_back( current ); Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) ); Elf_Word descsz = convertor( *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); current += (Elf_Xword)3 * sizeof( Elf_Word ) + ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; } } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* note_section; std::vector note_start_positions; }; using note_section_accessor = note_section_accessor_template
; using const_note_section_accessor = note_section_accessor_template; } // namespace ELFIO #endif // ELFIO_NOTE_HPP /*** End of inlined file: elfio_note.hpp ***/ /*** Start of inlined file: elfio_relocation.hpp ***/ #ifndef ELFIO_RELOCATION_HPP #define ELFIO_RELOCATION_HPP namespace ELFIO { template struct get_sym_and_type; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF32_R_SYM( (Elf_Word)info ); } static int get_r_type( Elf_Xword info ) { return ELF32_R_TYPE( (Elf_Word)info ); } }; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF32_R_SYM( (Elf_Word)info ); } static int get_r_type( Elf_Xword info ) { return ELF32_R_TYPE( (Elf_Word)info ); } }; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } }; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } }; //------------------------------------------------------------------------------ template class relocation_section_accessor_template { public: //------------------------------------------------------------------------------ relocation_section_accessor_template( const elfio& elf_file_, S* section_ ) : elf_file( elf_file_ ), relocation_section( section_ ) { } //------------------------------------------------------------------------------ Elf_Xword get_entries_num() const { Elf_Xword nRet = 0; if ( 0 != relocation_section->get_entry_size() ) { nRet = relocation_section->get_size() / relocation_section->get_entry_size(); } return nRet; } //------------------------------------------------------------------------------ bool get_entry( Elf_Xword index, Elf64_Addr& offset, Elf_Word& symbol, Elf_Word& type, Elf_Sxword& addend ) const { if ( index >= get_entries_num() ) { // Is index valid return false; } if ( elf_file.get_class() == ELFCLASS32 ) { if ( SHT_REL == relocation_section->get_type() ) { generic_get_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_get_entry_rela( index, offset, symbol, type, addend ); } } else { if ( SHT_REL == relocation_section->get_type() ) { generic_get_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_get_entry_rela( index, offset, symbol, type, addend ); } } return true; } //------------------------------------------------------------------------------ bool get_entry( Elf_Xword index, Elf64_Addr& offset, Elf64_Addr& symbolValue, std::string& symbolName, Elf_Word& type, Elf_Sxword& addend, Elf_Sxword& calcValue ) const { // Do regular job Elf_Word symbol; bool ret = get_entry( index, offset, symbol, type, addend ); // Find the symbol Elf_Xword size; unsigned char bind; unsigned char symbolType; Elf_Half section; unsigned char other; symbol_section_accessor symbols( elf_file, elf_file.sections[get_symbol_table_index()] ); ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size, bind, symbolType, section, other ); if ( ret ) { // Was it successful? switch ( type ) { case R_386_NONE: // none calcValue = 0; break; case R_386_32: // S + A calcValue = symbolValue + addend; break; case R_386_PC32: // S + A - P calcValue = symbolValue + addend - offset; break; case R_386_GOT32: // G + A - P calcValue = 0; break; case R_386_PLT32: // L + A - P calcValue = 0; break; case R_386_COPY: // none calcValue = 0; break; case R_386_GLOB_DAT: // S case R_386_JMP_SLOT: // S calcValue = symbolValue; break; case R_386_RELATIVE: // B + A calcValue = addend; break; case R_386_GOTOFF: // S + A - GOT calcValue = 0; break; case R_386_GOTPC: // GOT + A - P calcValue = 0; break; default: // Not recognized symbol! calcValue = 0; break; } } return ret; } //------------------------------------------------------------------------------ bool set_entry( Elf_Xword index, Elf64_Addr offset, Elf_Word symbol, Elf_Word type, Elf_Sxword addend ) { if ( index >= get_entries_num() ) { // Is index valid return false; } if ( elf_file.get_class() == ELFCLASS32 ) { if ( SHT_REL == relocation_section->get_type() ) { generic_set_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_set_entry_rela( index, offset, symbol, type, addend ); } } else { if ( SHT_REL == relocation_section->get_type() ) { generic_set_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_set_entry_rela( index, offset, symbol, type, addend ); } } return true; } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Xword info ) { if ( elf_file.get_class() == ELFCLASS32 ) { generic_add_entry( offset, info ); } else { generic_add_entry( offset, info ); } } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type ) { Elf_Xword info; if ( elf_file.get_class() == ELFCLASS32 ) { info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } add_entry( offset, info ); } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) { if ( elf_file.get_class() == ELFCLASS32 ) { generic_add_entry( offset, info, addend ); } else { generic_add_entry( offset, info, addend ); } } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type, Elf_Sxword addend ) { Elf_Xword info; if ( elf_file.get_class() == ELFCLASS32 ) { info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } add_entry( offset, info, addend ); } //------------------------------------------------------------------------------ void add_entry( string_section_accessor str_writer, const char* str, symbol_section_accessor sym_writer, Elf64_Addr value, Elf_Word size, unsigned char sym_info, unsigned char other, Elf_Half shndx, Elf64_Addr offset, unsigned char type ) { Elf_Word str_index = str_writer.add_string( str ); Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, sym_info, other, shndx ); add_entry( offset, sym_index, type ); } //------------------------------------------------------------------------------ void swap_symbols( Elf_Xword first, Elf_Xword second ) { Elf64_Addr offset; Elf_Word symbol; Elf_Word rtype; Elf_Sxword addend; for ( Elf_Word i = 0; i < get_entries_num(); i++ ) { get_entry( i, offset, symbol, rtype, addend ); if ( symbol == first ) { set_entry( i, offset, (Elf_Word)second, rtype, addend ); } if ( symbol == second ) { set_entry( i, offset, (Elf_Word)first, rtype, addend ); } } } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ Elf_Half get_symbol_table_index() const { return (Elf_Half)relocation_section->get_link(); } //------------------------------------------------------------------------------ template void generic_get_entry_rel( Elf_Xword index, Elf64_Addr& offset, Elf_Word& symbol, Elf_Word& type, Elf_Sxword& addend ) const { const endianess_convertor& convertor = elf_file.get_convertor(); const T* pEntry = reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ); offset = convertor( pEntry->r_offset ); Elf_Xword tmp = convertor( pEntry->r_info ); symbol = get_sym_and_type::get_r_sym( tmp ); type = get_sym_and_type::get_r_type( tmp ); addend = 0; } //------------------------------------------------------------------------------ template void generic_get_entry_rela( Elf_Xword index, Elf64_Addr& offset, Elf_Word& symbol, Elf_Word& type, Elf_Sxword& addend ) const { const endianess_convertor& convertor = elf_file.get_convertor(); const T* pEntry = reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ); offset = convertor( pEntry->r_offset ); Elf_Xword tmp = convertor( pEntry->r_info ); symbol = get_sym_and_type::get_r_sym( tmp ); type = get_sym_and_type::get_r_type( tmp ); addend = convertor( pEntry->r_addend ); } //------------------------------------------------------------------------------ template void generic_set_entry_rel( Elf_Xword index, Elf64_Addr offset, Elf_Word symbol, Elf_Word type, Elf_Sxword ) { const endianess_convertor& convertor = elf_file.get_convertor(); T* pEntry = const_cast( reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ) ); if ( elf_file.get_class() == ELFCLASS32 ) { pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } pEntry->r_offset = offset; pEntry->r_offset = convertor( pEntry->r_offset ); pEntry->r_info = convertor( pEntry->r_info ); } //------------------------------------------------------------------------------ template void generic_set_entry_rela( Elf_Xword index, Elf64_Addr offset, Elf_Word symbol, Elf_Word type, Elf_Sxword addend ) { const endianess_convertor& convertor = elf_file.get_convertor(); T* pEntry = const_cast( reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ) ); if ( elf_file.get_class() == ELFCLASS32 ) { pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } pEntry->r_offset = offset; pEntry->r_addend = addend; pEntry->r_offset = convertor( pEntry->r_offset ); pEntry->r_info = convertor( pEntry->r_info ); pEntry->r_addend = convertor( pEntry->r_addend ); } //------------------------------------------------------------------------------ template void generic_add_entry( Elf64_Addr offset, Elf_Xword info ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; entry.r_offset = offset; entry.r_info = info; entry.r_offset = convertor( entry.r_offset ); entry.r_info = convertor( entry.r_info ); relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); } //------------------------------------------------------------------------------ template void generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; entry.r_offset = offset; entry.r_info = info; entry.r_addend = addend; entry.r_offset = convertor( entry.r_offset ); entry.r_info = convertor( entry.r_info ); entry.r_addend = convertor( entry.r_addend ); relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* relocation_section; }; using relocation_section_accessor = relocation_section_accessor_template
; using const_relocation_section_accessor = relocation_section_accessor_template; } // namespace ELFIO #endif // ELFIO_RELOCATION_HPP /*** End of inlined file: elfio_relocation.hpp ***/ /*** Start of inlined file: elfio_dynamic.hpp ***/ #ifndef ELFIO_DYNAMIC_HPP #define ELFIO_DYNAMIC_HPP namespace ELFIO { //------------------------------------------------------------------------------ template class dynamic_section_accessor_template { public: //------------------------------------------------------------------------------ dynamic_section_accessor_template( const elfio& elf_file_, S* section_ ) : elf_file( elf_file_ ), dynamic_section( section_ ) { } //------------------------------------------------------------------------------ Elf_Xword get_entries_num() const { Elf_Xword nRet = 0; if ( 0 != dynamic_section->get_entry_size() ) { nRet = dynamic_section->get_size() / dynamic_section->get_entry_size(); } return nRet; } //------------------------------------------------------------------------------ bool get_entry( Elf_Xword index, Elf_Xword& tag, Elf_Xword& value, std::string& str ) const { if ( index >= get_entries_num() ) { // Is index valid return false; } if ( elf_file.get_class() == ELFCLASS32 ) { generic_get_entry_dyn( index, tag, value ); } else { generic_get_entry_dyn( index, tag, value ); } // If the tag may have a string table reference, prepare the string if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || tag == DT_RUNPATH ) { string_section_accessor strsec = elf_file.sections[get_string_table_index()]; const char* result = strsec.get_string( value ); if ( 0 == result ) { str.clear(); return false; } str = result; } else { str.clear(); } return true; } //------------------------------------------------------------------------------ void add_entry( Elf_Xword tag, Elf_Xword value ) { if ( elf_file.get_class() == ELFCLASS32 ) { generic_add_entry( tag, value ); } else { generic_add_entry( tag, value ); } } //------------------------------------------------------------------------------ void add_entry( Elf_Xword tag, const std::string& str ) { string_section_accessor strsec = elf_file.sections[get_string_table_index()]; Elf_Xword value = strsec.add_string( str ); add_entry( tag, value ); } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ Elf_Half get_string_table_index() const { return (Elf_Half)dynamic_section->get_link(); } //------------------------------------------------------------------------------ template void generic_get_entry_dyn( Elf_Xword index, Elf_Xword& tag, Elf_Xword& value ) const { const endianess_convertor& convertor = elf_file.get_convertor(); // Check unusual case when dynamic section has no data if ( dynamic_section->get_data() == 0 || ( index + 1 ) * dynamic_section->get_entry_size() > dynamic_section->get_size() ) { tag = DT_NULL; value = 0; return; } const T* pEntry = reinterpret_cast( dynamic_section->get_data() + index * dynamic_section->get_entry_size() ); tag = convertor( pEntry->d_tag ); switch ( tag ) { case DT_NULL: case DT_SYMBOLIC: case DT_TEXTREL: case DT_BIND_NOW: value = 0; break; case DT_NEEDED: case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_SONAME: case DT_RPATH: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_RUNPATH: case DT_FLAGS: case DT_PREINIT_ARRAYSZ: value = convertor( pEntry->d_un.d_val ); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_RELA: case DT_INIT: case DT_FINI: case DT_REL: case DT_DEBUG: case DT_JMPREL: case DT_INIT_ARRAY: case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: default: value = convertor( pEntry->d_un.d_ptr ); break; } } //------------------------------------------------------------------------------ template void generic_add_entry( Elf_Xword tag, Elf_Xword value ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; switch ( tag ) { case DT_NULL: case DT_SYMBOLIC: case DT_TEXTREL: case DT_BIND_NOW: value = 0; case DT_NEEDED: case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_SONAME: case DT_RPATH: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_RUNPATH: case DT_FLAGS: case DT_PREINIT_ARRAYSZ: entry.d_un.d_val = convertor( value ); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_RELA: case DT_INIT: case DT_FINI: case DT_REL: case DT_DEBUG: case DT_JMPREL: case DT_INIT_ARRAY: case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: default: entry.d_un.d_ptr = convertor( value ); break; } entry.d_tag = convertor( tag ); dynamic_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* dynamic_section; }; using dynamic_section_accessor = dynamic_section_accessor_template
; using const_dynamic_section_accessor = dynamic_section_accessor_template; } // namespace ELFIO #endif // ELFIO_DYNAMIC_HPP /*** End of inlined file: elfio_dynamic.hpp ***/ /*** Start of inlined file: elfio_modinfo.hpp ***/ #ifndef ELFIO_MODINFO_HPP #define ELFIO_MODINFO_HPP #include #include namespace ELFIO { //------------------------------------------------------------------------------ template class modinfo_section_accessor_template { public: //------------------------------------------------------------------------------ modinfo_section_accessor_template( S* section_ ) : modinfo_section( section_ ) { process_section(); } //------------------------------------------------------------------------------ Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } //------------------------------------------------------------------------------ bool get_attribute( Elf_Word no, std::string& field, std::string& value ) const { if ( no < content.size() ) { field = content[no].first; value = content[no].second; return true; } return false; } //------------------------------------------------------------------------------ bool get_attribute( std::string field_name, std::string& value ) const { for ( auto i = content.begin(); i != content.end(); i++ ) { if ( field_name == i->first ) { value = i->second; return true; } } return false; } //------------------------------------------------------------------------------ Elf_Word add_attribute( std::string field, std::string value ) { Elf_Word current_position = 0; if ( modinfo_section ) { // Strings are addeded to the end of the current section data current_position = (Elf_Word)modinfo_section->get_size(); std::string attribute = field + "=" + value; modinfo_section->append_data( attribute + '\0' ); content.push_back( std::pair( field, value ) ); } return current_position; } //------------------------------------------------------------------------------ private: void process_section() { const char* pdata = modinfo_section->get_data(); if ( pdata ) { ELFIO::Elf_Xword i = 0; while ( i < modinfo_section->get_size() ) { while ( i < modinfo_section->get_size() && !pdata[i] ) i++; if ( i < modinfo_section->get_size() ) { std::string info = pdata + i; size_t loc = info.find( '=' ); std::pair attribute( info.substr( 0, loc ), info.substr( loc + 1 ) ); content.push_back( attribute ); i += info.length(); } } } } //------------------------------------------------------------------------------ private: S* modinfo_section; std::vector> content; }; using modinfo_section_accessor = modinfo_section_accessor_template
; using const_modinfo_section_accessor = modinfo_section_accessor_template; } // namespace ELFIO #endif // ELFIO_MODINFO_HPP /*** End of inlined file: elfio_modinfo.hpp ***/ #ifdef _MSC_VER #pragma warning( pop ) #endif #endif // ELFIO_HPP /*** End of inlined file: elfio.hpp ***/ namespace ELFIO { static struct class_table_t { const char key; const char* str; } class_table[] = { { ELFCLASS32, "ELF32" }, { ELFCLASS64, "ELF64" }, }; static struct endian_table_t { const char key; const char* str; } endian_table[] = { { ELFDATANONE, "None" }, { ELFDATA2LSB, "Little endian" }, { ELFDATA2MSB, "Big endian" }, }; static struct version_table_t { const Elf64_Word key; const char* str; } version_table[] = { { EV_NONE, "None" }, { EV_CURRENT, "Current" }, }; static struct type_table_t { const Elf32_Half key; const char* str; } type_table[] = { { ET_NONE, "No file type" }, { ET_REL, "Relocatable file" }, { ET_EXEC, "Executable file" }, { ET_DYN, "Shared object file" }, { ET_CORE, "Core file" }, }; static struct machine_table_t { const Elf64_Half key; const char* str; } machine_table[] = { { EM_NONE, "No machine" }, { EM_M32, "AT&T WE 32100" }, { EM_SPARC, "SUN SPARC" }, { EM_386, "Intel 80386" }, { EM_68K, "Motorola m68k family" }, { EM_88K, "Motorola m88k family" }, { EM_486, "Intel 80486// Reserved for future use" }, { EM_860, "Intel 80860" }, { EM_MIPS, "MIPS R3000 (officially, big-endian only)" }, { EM_S370, "IBM System/370" }, { EM_MIPS_RS3_LE, "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, { EM_res011, "Reserved" }, { EM_res012, "Reserved" }, { EM_res013, "Reserved" }, { EM_res014, "Reserved" }, { EM_PARISC, "HPPA" }, { EM_res016, "Reserved" }, { EM_VPP550, "Fujitsu VPP500" }, { EM_SPARC32PLUS, "Sun's v8plus" }, { EM_960, "Intel 80960" }, { EM_PPC, "PowerPC" }, { EM_PPC64, "64-bit PowerPC" }, { EM_S390, "IBM S/390" }, { EM_SPU, "Sony/Toshiba/IBM SPU" }, { EM_res024, "Reserved" }, { EM_res025, "Reserved" }, { EM_res026, "Reserved" }, { EM_res027, "Reserved" }, { EM_res028, "Reserved" }, { EM_res029, "Reserved" }, { EM_res030, "Reserved" }, { EM_res031, "Reserved" }, { EM_res032, "Reserved" }, { EM_res033, "Reserved" }, { EM_res034, "Reserved" }, { EM_res035, "Reserved" }, { EM_V800, "NEC V800 series" }, { EM_FR20, "Fujitsu FR20" }, { EM_RH32, "TRW RH32" }, { EM_MCORE, "Motorola M*Core // May also be taken by Fujitsu MMA" }, { EM_RCE, "Old name for MCore" }, { EM_ARM, "ARM" }, { EM_OLD_ALPHA, "Digital Alpha" }, { EM_SH, "Renesas (formerly Hitachi) / SuperH SH" }, { EM_SPARCV9, "SPARC v9 64-bit" }, { EM_TRICORE, "Siemens Tricore embedded processor" }, { EM_ARC, "ARC Cores" }, { EM_H8_300, "Renesas (formerly Hitachi) H8/300" }, { EM_H8_300H, "Renesas (formerly Hitachi) H8/300H" }, { EM_H8S, "Renesas (formerly Hitachi) H8S" }, { EM_H8_500, "Renesas (formerly Hitachi) H8/500" }, { EM_IA_64, "Intel IA-64 Processor" }, { EM_MIPS_X, "Stanford MIPS-X" }, { EM_COLDFIRE, "Motorola Coldfire" }, { EM_68HC12, "Motorola M68HC12" }, { EM_MMA, "Fujitsu Multimedia Accelerator" }, { EM_PCP, "Siemens PCP" }, { EM_NCPU, "Sony nCPU embedded RISC processor" }, { EM_NDR1, "Denso NDR1 microprocesspr" }, { EM_STARCORE, "Motorola Star*Core processor" }, { EM_ME16, "Toyota ME16 processor" }, { EM_ST100, "STMicroelectronics ST100 processor" }, { EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor" }, { EM_X86_64, "Advanced Micro Devices X86-64 processor" }, { EM_PDSP, "Sony DSP Processor" }, { EM_PDP10, "Digital Equipment Corp. PDP-10" }, { EM_PDP11, "Digital Equipment Corp. PDP-11" }, { EM_FX66, "Siemens FX66 microcontroller" }, { EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller" }, { EM_ST7, "STMicroelectronics ST7 8-bit microcontroller" }, { EM_68HC16, "Motorola MC68HC16 Microcontroller" }, { EM_68HC11, "Motorola MC68HC11 Microcontroller" }, { EM_68HC08, "Motorola MC68HC08 Microcontroller" }, { EM_68HC05, "Motorola MC68HC05 Microcontroller" }, { EM_SVX, "Silicon Graphics SVx" }, { EM_ST19, "STMicroelectronics ST19 8-bit cpu" }, { EM_VAX, "Digital VAX" }, { EM_CRIS, "Axis Communications 32-bit embedded processor" }, { EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu" }, { EM_FIREPATH, "Element 14 64-bit DSP processor" }, { EM_ZSP, "LSI Logic's 16-bit DSP processor" }, { EM_MMIX, "Donald Knuth's educational 64-bit processor" }, { EM_HUANY, "Harvard's machine-independent format" }, { EM_PRISM, "SiTera Prism" }, { EM_AVR, "Atmel AVR 8-bit microcontroller" }, { EM_FR30, "Fujitsu FR30" }, { EM_D10V, "Mitsubishi D10V" }, { EM_D30V, "Mitsubishi D30V" }, { EM_V850, "NEC v850" }, { EM_M32R, "Renesas M32R (formerly Mitsubishi M32R)" }, { EM_MN10300, "Matsushita MN10300" }, { EM_MN10200, "Matsushita MN10200" }, { EM_PJ, "picoJava" }, { EM_OPENRISC, "OpenRISC 32-bit embedded processor" }, { EM_ARC_A5, "ARC Cores Tangent-A5" }, { EM_XTENSA, "Tensilica Xtensa Architecture" }, { EM_VIDEOCORE, "Alphamosaic VideoCore processor" }, { EM_TMM_GPP, "Thompson Multimedia General Purpose Processor" }, { EM_NS32K, "National Semiconductor 32000 series" }, { EM_TPC, "Tenor Network TPC processor" }, { EM_SNP1K, "Trebia SNP 1000 processor" }, { EM_ST200, "STMicroelectronics ST200 microcontroller" }, { EM_IP2K, "Ubicom IP2022 micro controller" }, { EM_MAX, "MAX Processor" }, { EM_CR, "National Semiconductor CompactRISC" }, { EM_F2MC16, "Fujitsu F2MC16" }, { EM_MSP430, "TI msp430 micro controller" }, { EM_BLACKFIN, "ADI Blackfin" }, { EM_SE_C33, "S1C33 Family of Seiko Epson processors" }, { EM_SEP, "Sharp embedded microprocessor" }, { EM_ARCA, "Arca RISC Microprocessor" }, { EM_UNICORE, "Microprocessor series from PKU-Unity Ltd. and MPRC of " "Peking University" }, { EM_EXCESS, "eXcess: 16/32/64-bit configurable embedded CPU" }, { EM_DXP, "Icera Semiconductor Inc. Deep Execution Processor" }, { EM_ALTERA_NIOS2, "Altera Nios II soft-core processor" }, { EM_CRX, "National Semiconductor CRX" }, { EM_XGATE, "Motorola XGATE embedded processor" }, { EM_C166, "Infineon C16x/XC16x processor" }, { EM_M16C, "Renesas M16C series microprocessors" }, { EM_DSPIC30F, "Microchip Technology dsPIC30F Digital Signal Controller" }, { EM_CE, "Freescale Communication Engine RISC core" }, { EM_M32C, "Renesas M32C series microprocessors" }, { EM_res121, "Reserved" }, { EM_res122, "Reserved" }, { EM_res123, "Reserved" }, { EM_res124, "Reserved" }, { EM_res125, "Reserved" }, { EM_res126, "Reserved" }, { EM_res127, "Reserved" }, { EM_res128, "Reserved" }, { EM_res129, "Reserved" }, { EM_res130, "Reserved" }, { EM_TSK3000, "Altium TSK3000 core" }, { EM_RS08, "Freescale RS08 embedded processor" }, { EM_res133, "Reserved" }, { EM_ECOG2, "Cyan Technology eCOG2 microprocessor" }, { EM_SCORE, "Sunplus Score" }, { EM_SCORE7, "Sunplus S+core7 RISC processor" }, { EM_DSP24, "New Japan Radio (NJR) 24-bit DSP Processor" }, { EM_VIDEOCORE3, "Broadcom VideoCore III processor" }, { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, { EM_SE_C17, "Seiko Epson C17 family" }, { EM_TI_C6000, "Texas Instruments TMS320C6000 DSP family" }, { EM_TI_C2000, "Texas Instruments TMS320C2000 DSP family" }, { EM_TI_C5500, "Texas Instruments TMS320C55x DSP family" }, { EM_res143, "Reserved" }, { EM_res144, "Reserved" }, { EM_res145, "Reserved" }, { EM_res146, "Reserved" }, { EM_res147, "Reserved" }, { EM_res148, "Reserved" }, { EM_res149, "Reserved" }, { EM_res150, "Reserved" }, { EM_res151, "Reserved" }, { EM_res152, "Reserved" }, { EM_res153, "Reserved" }, { EM_res154, "Reserved" }, { EM_res155, "Reserved" }, { EM_res156, "Reserved" }, { EM_res157, "Reserved" }, { EM_res158, "Reserved" }, { EM_res159, "Reserved" }, { EM_MMDSP_PLUS, "STMicroelectronics 64bit VLIW Data Signal Processor" }, { EM_CYPRESS_M8C, "Cypress M8C microprocessor" }, { EM_R32C, "Renesas R32C series microprocessors" }, { EM_TRIMEDIA, "NXP Semiconductors TriMedia architecture family" }, { EM_QDSP6, "QUALCOMM DSP6 Processor" }, { EM_8051, "Intel 8051 and variants" }, { EM_STXP7X, "STMicroelectronics STxP7x family" }, { EM_NDS32, "Andes Technology compact code size embedded RISC processor family" }, { EM_ECOG1, "Cyan Technology eCOG1X family" }, { EM_ECOG1X, "Cyan Technology eCOG1X family" }, { EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, { EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor" }, { EM_MANIK, "M2000 Reconfigurable RISC Microprocessor" }, { EM_CRAYNV2, "Cray Inc. NV2 vector architecture" }, { EM_RX, "Renesas RX family" }, { EM_METAG, "Imagination Technologies META processor architecture" }, { EM_MCST_ELBRUS, "MCST Elbrus general purpose hardware architecture" }, { EM_ECOG16, "Cyan Technology eCOG16 family" }, { EM_CR16, "National Semiconductor CompactRISC 16-bit processor" }, { EM_ETPU, "Freescale Extended Time Processing Unit" }, { EM_SLE9X, "Infineon Technologies SLE9X core" }, { EM_L1OM, "Intel L1OM" }, { EM_INTEL181, "Reserved by Intel" }, { EM_INTEL182, "Reserved by Intel" }, { EM_res183, "Reserved by ARM" }, { EM_res184, "Reserved by ARM" }, { EM_AVR32, "Atmel Corporation 32-bit microprocessor family" }, { EM_STM8, "STMicroeletronics STM8 8-bit microcontroller" }, { EM_TILE64, "Tilera TILE64 multicore architecture family" }, { EM_TILEPRO, "Tilera TILEPro multicore architecture family" }, { EM_MICROBLAZE, "Xilinx MicroBlaze 32-bit RISC soft processor core" }, { EM_CUDA, "NVIDIA CUDA architecture " }, }; static struct section_type_table_t { const Elf64_Half key; const char* str; } section_type_table[] = { { SHT_NULL, "NULL" }, { SHT_PROGBITS, "PROGBITS" }, { SHT_SYMTAB, "SYMTAB" }, { SHT_STRTAB, "STRTAB" }, { SHT_RELA, "RELA" }, { SHT_HASH, "HASH" }, { SHT_DYNAMIC, "DYNAMIC" }, { SHT_NOTE, "NOTE" }, { SHT_NOBITS, "NOBITS" }, { SHT_REL, "REL" }, { SHT_SHLIB, "SHLIB" }, { SHT_DYNSYM, "DYNSYM" }, { SHT_INIT_ARRAY, "INIT_ARRAY" }, { SHT_FINI_ARRAY, "FINI_ARRAY" }, { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, { SHT_GROUP, "GROUP" }, { SHT_SYMTAB_SHNDX, "SYMTAB_SHNDX " }, }; static struct segment_type_table_t { const Elf_Word key; const char* str; } segment_type_table[] = { { PT_NULL, "NULL" }, { PT_LOAD, "LOAD" }, { PT_DYNAMIC, "DYNAMIC" }, { PT_INTERP, "INTERP" }, { PT_NOTE, "NOTE" }, { PT_SHLIB, "SHLIB" }, { PT_PHDR, "PHDR" }, { PT_TLS, "TLS" }, }; static struct segment_flag_table_t { const Elf_Word key; const char* str; } segment_flag_table[] = { { 0, "" }, { 1, "X" }, { 2, "W" }, { 3, "WX" }, { 4, "R" }, { 5, "RX" }, { 6, "RW" }, { 7, "RWX" }, }; static struct symbol_bind_t { const Elf_Word key; const char* str; } symbol_bind_table[] = { { STB_LOCAL, "LOCAL" }, { STB_GLOBAL, "GLOBAL" }, { STB_WEAK, "WEAK" }, { STB_LOOS, "LOOS" }, { STB_HIOS, "HIOS" }, { STB_MULTIDEF, "MULTIDEF" }, { STB_LOPROC, "LOPROC" }, { STB_HIPROC, "HIPROC" }, }; static struct symbol_type_t { const Elf_Word key; const char* str; } symbol_type_table[] = { { STT_NOTYPE, "NOTYPE" }, { STT_OBJECT, "OBJECT" }, { STT_FUNC, "FUNC" }, { STT_SECTION, "SECTION" }, { STT_FILE, "FILE" }, { STT_COMMON, "COMMON" }, { STT_TLS, "TLS" }, { STT_LOOS, "LOOS" }, { STT_HIOS, "HIOS" }, { STT_LOPROC, "LOPROC" }, { STT_HIPROC, "HIPROC" }, }; static struct dynamic_tag_t { const Elf_Word key; const char* str; } dynamic_tag_table[] = { { DT_NULL, "NULL" }, { DT_NEEDED, "NEEDED" }, { DT_PLTRELSZ, "PLTRELSZ" }, { DT_PLTGOT, "PLTGOT" }, { DT_HASH, "HASH" }, { DT_STRTAB, "STRTAB" }, { DT_SYMTAB, "SYMTAB" }, { DT_RELA, "RELA" }, { DT_RELASZ, "RELASZ" }, { DT_RELAENT, "RELAENT" }, { DT_STRSZ, "STRSZ" }, { DT_SYMENT, "SYMENT" }, { DT_INIT, "INIT" }, { DT_FINI, "FINI" }, { DT_SONAME, "SONAME" }, { DT_RPATH, "RPATH" }, { DT_SYMBOLIC, "SYMBOLIC" }, { DT_REL, "REL" }, { DT_RELSZ, "RELSZ" }, { DT_RELENT, "RELENT" }, { DT_PLTREL, "PLTREL" }, { DT_DEBUG, "DEBUG" }, { DT_TEXTREL, "TEXTREL" }, { DT_JMPREL, "JMPREL" }, { DT_BIND_NOW, "BIND_NOW" }, { DT_INIT_ARRAY, "INIT_ARRAY" }, { DT_FINI_ARRAY, "FINI_ARRAY" }, { DT_INIT_ARRAYSZ, "INIT_ARRAYSZ" }, { DT_FINI_ARRAYSZ, "FINI_ARRAYSZ" }, { DT_RUNPATH, "RUNPATH" }, { DT_FLAGS, "FLAGS" }, { DT_ENCODING, "ENCODING" }, { DT_PREINIT_ARRAY, "PREINIT_ARRAY" }, { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, { DT_MAXPOSTAGS, "MAXPOSTAGS" }, }; static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; //------------------------------------------------------------------------------ class dump { #define DUMP_DEC_FORMAT( width ) \ std::setw( width ) << std::setfill( ' ' ) << std::dec << std::right #define DUMP_HEX_FORMAT( width ) \ std::setw( width ) << std::setfill( '0' ) << std::hex << std::right #define DUMP_STR_FORMAT( width ) \ std::setw( width ) << std::setfill( ' ' ) << std::hex << std::left public: //------------------------------------------------------------------------------ static void header( std::ostream& out, const elfio& reader ) { if ( !reader.get_header_size() ) { return; } out << "ELF Header" << std::endl << std::endl << " Class: " << str_class( reader.get_class() ) << std::endl << " Encoding: " << str_endian( reader.get_encoding() ) << std::endl << " ELFVersion: " << str_version( reader.get_elf_version() ) << std::endl << " Type: " << str_type( reader.get_type() ) << std::endl << " Machine: " << str_machine( reader.get_machine() ) << std::endl << " Version: " << str_version( reader.get_version() ) << std::endl << " Entry: " << "0x" << std::hex << reader.get_entry() << std::endl << " Flags: " << "0x" << std::hex << reader.get_flags() << std::endl << std::endl; } //------------------------------------------------------------------------------ static void section_headers( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); if ( n == 0 ) { return; } out << "Section Headers:" << std::endl; if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit out << "[ Nr ] Type Addr Size ES Flg Lk Inf " "Al Name" << std::endl; } else { // Output for 64-bit out << "[ Nr ] Type Addr Size " " ES Flg" << std::endl << " Lk Inf Al Name" << std::endl; } for ( Elf_Half i = 0; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; section_header( out, i, sec, reader.get_class() ); } out << "Key to Flags: W (write), A (alloc), X (execute)\n\n" << std::endl; } //------------------------------------------------------------------------------ static void section_header( std::ostream& out, Elf_Half no, const section* sec, unsigned char elf_class ) { std::ios_base::fmtflags original_flags = out.flags(); if ( elf_class == ELFCLASS32 ) { // Output for 32-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " << DUMP_HEX_FORMAT( 8 ) << sec->get_address() << " " << DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " " << DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " " << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " " << DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " " << DUMP_HEX_FORMAT( 2 ) << sec->get_addr_align() << " " << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl; } else { // Output for 64-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " << DUMP_HEX_FORMAT( 16 ) << sec->get_address() << " " << DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " " << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " << std::endl << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << " " << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl; } out.flags( original_flags ); return; } //------------------------------------------------------------------------------ static void segment_headers( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.segments.size(); if ( n == 0 ) { return; } out << "Segment headers:" << std::endl; if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit out << "[ Nr ] Type VirtAddr PhysAddr FileSize Mem.Size " "Flags Align" << std::endl; } else { // Output for 64-bit out << "[ Nr ] Type VirtAddr PhysAddr " "Flags" << std::endl << " FileSize Mem.Size " "Align" << std::endl; } for ( Elf_Half i = 0; i < n; ++i ) { segment* seg = reader.segments[i]; segment_header( out, i, seg, reader.get_class() ); } out << std::endl; } //------------------------------------------------------------------------------ static void segment_header( std::ostream& out, Elf_Half no, const segment* seg, unsigned int elf_class ) { std::ios_base::fmtflags original_flags = out.flags(); if ( elf_class == ELFCLASS32 ) { // Output for 32-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_virtual_address() << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address() << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " " << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_align() << " " << std::endl; } else { // Output for 64-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_virtual_address() << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address() << " " << DUMP_STR_FORMAT( 16 ) << str_segment_flag( seg->get_flags() ) << " " << std::endl << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_file_size() << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_memory_size() << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_align() << " " << std::endl; } out.flags( original_flags ); } //------------------------------------------------------------------------------ static void symbol_tables( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); for ( Elf_Half i = 0; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) { symbol_section_accessor symbols( reader, sec ); Elf_Xword sym_no = symbols.get_symbols_num(); if ( sym_no > 0 ) { out << "Symbol table (" << sec->get_name() << ")" << std::endl; if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit out << "[ Nr ] Value Size Type Bind " "Sect Name" << std::endl; } else { // Output for 64-bit out << "[ Nr ] Value Size Type " " Bind Sect" << std::endl << " Name" << std::endl; } for ( Elf_Xword i = 0; i < sym_no; ++i ) { std::string name; Elf64_Addr value = 0; Elf_Xword size = 0; unsigned char bind = 0; unsigned char type = 0; Elf_Half section = 0; unsigned char other = 0; symbols.get_symbol( i, name, value, size, bind, type, section, other ); symbol_table( out, i, name, value, size, bind, type, section, reader.get_class() ); } out << std::endl; } } } } //------------------------------------------------------------------------------ static void symbol_table( std::ostream& out, Elf_Xword no, std::string& name, Elf64_Addr value, Elf_Xword size, unsigned char bind, unsigned char type, Elf_Half section, unsigned int elf_class ) { std::ios_base::fmtflags original_flags = out.flags(); if ( elf_class == ELFCLASS32 ) { // Output for 32-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_HEX_FORMAT( 8 ) << value << " " << DUMP_HEX_FORMAT( 8 ) << size << " " << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 ) << section << " " << DUMP_STR_FORMAT( 1 ) << name << " " << std::endl; } else { // Output for 64-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_HEX_FORMAT( 16 ) << value << " " << DUMP_HEX_FORMAT( 16 ) << size << " " << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 ) << section << " " << std::endl << " " << DUMP_STR_FORMAT( 1 ) << name << " " << std::endl; } out.flags( original_flags ); } //------------------------------------------------------------------------------ static void notes( std::ostream& out, const elfio& reader ) { Elf_Half no = reader.sections.size(); for ( Elf_Half i = 0; i < no; ++i ) { // For all sections section* sec = reader.sections[i]; if ( SHT_NOTE == sec->get_type() ) { // Look at notes note_section_accessor notes( reader, sec ); Elf_Word no_notes = notes.get_notes_num(); if ( no > 0 ) { out << "Note section (" << sec->get_name() << ")" << std::endl << " No Type Name" << std::endl; for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes Elf_Word type; std::string name; void* desc; Elf_Word descsz; if ( notes.get_note( j, type, name, desc, descsz ) ) { // 'name' usually contains \0 at the end. Try to fix it name = name.c_str(); note( out, j, type, name ); } } out << std::endl; } } } } //------------------------------------------------------------------------------ static void modinfo( std::ostream& out, const elfio& reader ) { Elf_Half no = reader.sections.size(); for ( Elf_Half i = 0; i < no; ++i ) { // For all sections section* sec = reader.sections[i]; if ( ".modinfo" == sec->get_name() ) { // Look for the section out << "Section .modinfo" << std::endl; const_modinfo_section_accessor modinfo( sec ); for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) { std::string field; std::string value; if ( modinfo.get_attribute( i, field, value ) ) { out << " " << std::setw( 20 ) << field << std::setw( 0 ) << " = " << value << std::endl; } } out << std::endl; break; } } } //------------------------------------------------------------------------------ static void note( std::ostream& out, int no, Elf_Word type, const std::string& name ) { out << " [" << DUMP_DEC_FORMAT( 2 ) << no << "] " << DUMP_HEX_FORMAT( 8 ) << type << " " << DUMP_STR_FORMAT( 1 ) << name << std::endl; } //------------------------------------------------------------------------------ static void dynamic_tags( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); for ( Elf_Half i = 0; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; if ( SHT_DYNAMIC == sec->get_type() ) { dynamic_section_accessor dynamic( reader, sec ); Elf_Xword dyn_no = dynamic.get_entries_num(); if ( dyn_no > 0 ) { out << "Dynamic section (" << sec->get_name() << ")" << std::endl; out << "[ Nr ] Tag Name/Value" << std::endl; for ( Elf_Xword i = 0; i < dyn_no; ++i ) { Elf_Xword tag = 0; Elf_Xword value = 0; std::string str; dynamic.get_entry( i, tag, value, str ); dynamic_tag( out, i, tag, value, str, reader.get_class() ); if ( DT_NULL == tag ) { break; } } out << std::endl; } } } } //------------------------------------------------------------------------------ static void dynamic_tag( std::ostream& out, Elf_Xword no, Elf_Xword tag, Elf_Xword value, std::string str, unsigned int /*elf_class*/ ) { out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; if ( str.empty() ) { out << DUMP_HEX_FORMAT( 16 ) << value << " "; } else { out << DUMP_STR_FORMAT( 32 ) << str << " "; } out << std::endl; } //------------------------------------------------------------------------------ static void section_data( std::ostream& out, const section* sec ) { std::ios_base::fmtflags original_flags = out.flags(); out << sec->get_name() << std::endl; const char* pdata = sec->get_data(); if ( pdata ) { ELFIO::Elf_Xword i; for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); ++i ) { if ( i % 16 == 0 ) { out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; } out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); if ( i % 16 == 15 ) { out << std::endl; } } if ( i % 16 != 0 ) { out << std::endl; } out.flags( original_flags ); } return; } //------------------------------------------------------------------------------ static void section_datas( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); if ( n == 0 ) { return; } out << "Section Data:" << std::endl; for ( Elf_Half i = 1; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; if ( sec->get_type() == SHT_NOBITS ) { continue; } section_data( out, sec ); } out << std::endl; } //------------------------------------------------------------------------------ static void segment_data( std::ostream& out, Elf_Half no, const segment* seg ) { std::ios_base::fmtflags original_flags = out.flags(); out << "Segment # " << no << std::endl; const char* pdata = seg->get_data(); if ( pdata ) { ELFIO::Elf_Xword i; for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); ++i ) { if ( i % 16 == 0 ) { out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; } out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); if ( i % 16 == 15 ) { out << std::endl; } } if ( i % 16 != 0 ) { out << std::endl; } out.flags( original_flags ); } return; } //------------------------------------------------------------------------------ static void segment_datas( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.segments.size(); if ( n == 0 ) { return; } out << "Segment Data:" << std::endl; for ( Elf_Half i = 0; i < n; ++i ) { // For all sections segment* seg = reader.segments[i]; segment_data( out, i, seg ); } out << std::endl; } private: //------------------------------------------------------------------------------ template std::string static find_value_in_table( const T& table, const K& key ) { std::string res = "?"; for ( unsigned int i = 0; i < sizeof( table ) / sizeof( table[0] ); ++i ) { if ( table[i].key == key ) { res = table[i].str; break; } } return res; } //------------------------------------------------------------------------------ template static std::string format_assoc( const T& table, const K& key ) { std::string str = find_value_in_table( table, key ); if ( str == "?" ) { std::ostringstream oss; oss << str << " (0x" << std::hex << key << ")"; str = oss.str(); } return str; } //------------------------------------------------------------------------------ template static std::string format_assoc( const T& table, const char key ) { return format_assoc( table, (const int)key ); } //------------------------------------------------------------------------------ static std::string section_flags( Elf_Xword flags ) { std::string ret = ""; if ( flags & SHF_WRITE ) { ret += "W"; } if ( flags & SHF_ALLOC ) { ret += "A"; } if ( flags & SHF_EXECINSTR ) { ret += "X"; } return ret; } //------------------------------------------------------------------------------ #define STR_FUNC_TABLE( name ) \ template static std::string str_##name( const T key ) \ { \ return format_assoc( name##_table, key ); \ } STR_FUNC_TABLE( class ) STR_FUNC_TABLE( endian ) STR_FUNC_TABLE( version ) STR_FUNC_TABLE( type ) STR_FUNC_TABLE( machine ) STR_FUNC_TABLE( section_type ) STR_FUNC_TABLE( segment_type ) STR_FUNC_TABLE( segment_flag ) STR_FUNC_TABLE( symbol_bind ) STR_FUNC_TABLE( symbol_type ) STR_FUNC_TABLE( dynamic_tag ) #undef STR_FUNC_TABLE #undef DUMP_DEC_FORMAT #undef DUMP_HEX_FORMAT #undef DUMP_STR_FORMAT }; // class dump }; // namespace ELFIO #endif // ELFIO_DUMP_HPP /*** End of inlined file: elfio_dump.hpp ***/ ukui-biometric-auth/tests/kt-test-utils/cpp-stub/stub.h0000664000175000017500000002341715167732644022173 0ustar fengfeng#ifndef __STUB_H__ #define __STUB_H__ #ifdef _WIN32 //windows #include #include #else //linux #include #include #include #endif //c #include #include //c++ #include #define ADDR(CLASS_NAME,MEMBER_NAME) (&CLASS_NAME::MEMBER_NAME) /********************************************************** replace function **********************************************************/ #ifdef _WIN32 #define CACHEFLUSH(addr, size) FlushInstructionCache(GetCurrentProcess(), addr, size) #else #define CACHEFLUSH(addr, size) __builtin___clear_cache(addr, addr + size) #endif #if defined(__aarch64__) || defined(_M_ARM64) #define CODESIZE 16U #define CODESIZE_MIN 16U #define CODESIZE_MAX CODESIZE // ldr x9, +8 // br x9 // addr #define REPLACE_FAR(t, fn, fn_stub)\ ((uint32_t*)fn)[0] = 0x58000040 | 9;\ ((uint32_t*)fn)[1] = 0xd61f0120 | (9 << 5);\ *(long long *)(fn + 8) = (long long )fn_stub;\ CACHEFLUSH((char *)fn, CODESIZE); #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub) #elif defined(__arm__) || defined(_M_ARM) #define CODESIZE 8U #define CODESIZE_MIN 8U #define CODESIZE_MAX CODESIZE // ldr pc, [pc, #-4] #define REPLACE_FAR(t, fn, fn_stub)\ ((uint32_t*)fn)[0] = 0xe51ff004;\ ((uint32_t*)fn)[1] = (uint32_t)fn_stub;\ CACHEFLUSH((char *)fn, CODESIZE); #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub) #elif defined(__mips64) #define CACHEFLUSH(addr, size) __builtin___clear_cache(addr, addr + size) #define CODESIZE 80U #define CODESIZE_MIN 80U #define CODESIZE_MAX CODESIZE //mips没有PC指针,所以需要手动入栈出栈 //120000ce0: 67bdffe0 daddiu sp, sp, -32 //入栈 //120000ce4: ffbf0018 sd ra, 24(sp) //120000ce8: ffbe0010 sd s8, 16(sp) //120000cec: ffbc0008 sd gp, 8(sp) //120000cf0: 03a0f025 move s8, sp //120000d2c: 03c0e825 move sp, s8 //出栈 //120000d30: dfbf0018 ld ra, 24(sp) //120000d34: dfbe0010 ld s8, 16(sp) //120000d38: dfbc0008 ld gp, 8(sp) //120000d3c: 67bd0020 daddiu sp, sp, 32 //120000d40: 03e00008 jr ra #define REPLACE_FAR(t, fn, fn_stub)\ ((uint32_t *)fn)[0] = 0x67bdffe0;\ ((uint32_t *)fn)[1] = 0xffbf0018;\ ((uint32_t *)fn)[2] = 0xffbe0010;\ ((uint32_t *)fn)[3] = 0xffbc0008;\ ((uint32_t *)fn)[4] = 0x03a0f025;\ *(uint16_t *)(fn + 20) = (long long)fn_stub >> 32;\ *(fn + 22) = 0x19;\ *(fn + 23) = 0x24;\ ((uint32_t *)fn)[6] = 0x0019cc38;\ *(uint16_t *)(fn + 28) = (long long)fn_stub >> 16;\ *(fn + 30) = 0x39;\ *(fn + 31) = 0x37;\ ((uint32_t *)fn)[8] = 0x0019cc38;\ *(uint16_t *)(fn + 36) = (long long)fn_stub;\ *(fn + 38) = 0x39;\ *(fn + 39) = 0x37;\ ((uint32_t *)fn)[10] = 0x0320f809;\ ((uint32_t *)fn)[11] = 0x00000000;\ ((uint32_t *)fn)[12] = 0x00000000;\ ((uint32_t *)fn)[13] = 0x03c0e825;\ ((uint32_t *)fn)[14] = 0xdfbf0018;\ ((uint32_t *)fn)[15] = 0xdfbe0010;\ ((uint32_t *)fn)[16] = 0xdfbc0008;\ ((uint32_t *)fn)[17] = 0x67bd0020;\ ((uint32_t *)fn)[18] = 0x03e00008;\ ((uint32_t *)fn)[19] = 0x00000000;\ CACHEFLUSH((char *)fn, CODESIZE); #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub) #elif defined(__thumb__) || defined(_M_THUMB) #error "Thumb is not supported" #else //__i386__ _x86_64__ #define CODESIZE 13U #define CODESIZE_MIN 5U #define CODESIZE_MAX CODESIZE //13 byte(jmp m16:64) //movabs $0x102030405060708,%r11 //jmpq *%r11 static void REPLACE_FAR(void *t, char *fn, char *fn_stub) { *fn = 0x49; *(fn + 1) = 0xbb; *(long long *)(fn + 2) = (long long)fn_stub; *(fn + 10) = 0x41; *(fn + 11) = 0xff; *(fn + 12) = 0xe3; CACHEFLUSH((char *)fn, CODESIZE); } //5 byte(jmp rel32) #define REPLACE_NEAR(t, fn, fn_stub)\ *fn = 0xE9;\ *(int *)(fn + 1) = (int)(fn_stub - fn - CODESIZE_MIN);\ CACHEFLUSH((char *)fn, CODESIZE); #endif struct func_stub { char *fn; unsigned char code_buf[CODESIZE]; bool far_jmp; }; class Stub { public: Stub() { #ifdef _WIN32 SYSTEM_INFO sys_info; GetSystemInfo(&sys_info); m_pagesize = sys_info.dwPageSize; #else m_pagesize = sysconf(_SC_PAGE_SIZE); #endif if (m_pagesize < 0) { m_pagesize = 4096; } } ~Stub() { clear(); } virtual void clear() { std::map::iterator iter; struct func_stub *pstub; for(iter=m_result.begin(); iter != m_result.end(); iter++) { pstub = iter->second; #ifdef _WIN32 DWORD lpflOldProtect; if(0 != VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect)) #else if (0 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC)) #endif { if(pstub->far_jmp) { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX); } else { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN); } #ifdef _WIN32 VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect); #else CACHEFLUSH(pstub->fn,CODESIZE); mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC); #endif } iter->second = NULL; delete pstub; } m_result.clear(); return; } template bool set(T addr, S addr_stub) { char * fn; char * fn_stub; fn = addrof(addr); fn_stub = addrof(addr_stub); struct func_stub *pstub; std::map::iterator iter = m_result.find(fn); if (iter == m_result.end()) { pstub = new func_stub; //start pstub->fn = fn; if(distanceof(fn, fn_stub)) { pstub->far_jmp = true; std::memcpy(pstub->code_buf, fn, CODESIZE_MAX); } else { pstub->far_jmp = false; std::memcpy(pstub->code_buf, fn, CODESIZE_MIN); } } else { pstub = iter->second; pstub->far_jmp = distanceof(fn, fn_stub); } #ifdef _WIN32 DWORD lpflOldProtect; if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect)) #else if (-1 == mprotect(pageof(pstub->fn), static_cast(m_pagesize * 2), PROT_READ | PROT_WRITE | PROT_EXEC)) #endif { //throw("stub set memory protect to w+r+x faild"); return false; } if(pstub->far_jmp) { REPLACE_FAR(this, fn, fn_stub); } else { REPLACE_NEAR(this, fn, fn_stub); } #ifdef _WIN32 if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect)) #else if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC)) #endif { //throw("stub set memory protect to r+x failed"); return false; } m_result.insert(std::pair(fn,pstub)); return true; } template bool reset(T addr) { char * fn; fn = addrof(addr); std::map::iterator iter = m_result.find(fn); if (iter == m_result.end()) { return true; } struct func_stub *pstub; pstub = iter->second; #ifdef _WIN32 DWORD lpflOldProtect; if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect)) #else if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC)) #endif { //throw("stub reset memory protect to w+r+x faild"); return false; } if(pstub->far_jmp) { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX); } else { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN); } #ifdef _WIN32 if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect)) #else CACHEFLUSH(pstub->fn,CODESIZE); if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC)) #endif { //throw("stub reset memory protect to r+x failed"); return false; } m_result.erase(iter); delete pstub; return true; } protected: char *pageof(char* addr) { #ifdef _WIN32 return (char *)((unsigned long long)addr & ~(m_pagesize - 1)); #else return (char *)((unsigned long)addr & ~(m_pagesize - 1)); #endif } template char* addrof(T addr) { union { T _s; char* _d; }ut; ut._s = addr; return ut._d; } bool distanceof(char* addr, char* addr_stub) { std::ptrdiff_t diff = addr_stub >= addr ? addr_stub - addr : addr - addr_stub; if((sizeof(addr) > 4) && (((diff >> 31) - 1) > 0)) { return true; } return false; } protected: #ifdef _WIN32 //LLP64 long long m_pagesize; #else //LP64 long m_pagesize; #endif std::map m_result; }; #endif ukui-biometric-auth/tests/kt-test-utils/cpp-stub-ext/0000775000175000017500000000000015167732630021627 5ustar fengfengukui-biometric-auth/tests/kt-test-utils/cpp-stub-ext/stubext.h0000664000175000017500000000734115167732630023503 0ustar fengfeng #ifndef STUBEXT_H #define STUBEXT_H /* * Author: Zhang Yu * Maintainer: Zhang Yu * * MIT License * * Copyright (c) 2020 Zhang Yu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ //需修改Stub的私用成员函数和成员变量为保护类型 #include "stub.h" #include "stub-shadow.h" #ifdef DEBUG_STUB_INVOKE // use to make sure the stub function is invoked. # define __DBG_STUB_INVOKE__ printf("stub at %s:%d is invoked.\n", __FILE__, __LINE__); #else # define __DBG_STUB_INVOKE__ #endif #define VADDR(CLASS_NAME, MEMBER_NAME) (typename stub_ext::VFLocator::Func)(&CLASS_NAME::MEMBER_NAME) namespace stub_ext { class StubExt : public Stub { public: StubExt() : Stub() { } template bool set_lamda(T addr, Lamda lamda) { char *fn = addrof(addr); if (m_result.find(fn) != m_result.end()) reset(addr); Wrapper *wrapper = nullptr; auto addr_stub = depictShadow(&wrapper, addr, lamda); if (set(addr, addr_stub)) { m_wrappers.insert(std::make_pair(fn, wrapper)); return true; } else { freeWrapper(wrapper); } return false; } template void reset(T addr) { Stub::reset(addr); char *fn = addrof(addr); auto iter = m_wrappers.find(fn); if (iter != m_wrappers.end()) { freeWrapper(iter->second); m_wrappers.erase(iter); } } ~StubExt() { clear(); } void clear() override { Stub::clear(); for (auto iter = m_wrappers.begin(); iter != m_wrappers.end(); ++iter) { freeWrapper(iter->second); } m_wrappers.clear(); } template static void *get_ctor_addr(bool start = true) { // the start vairable must be true, or the compiler will optimize out. if (start) goto Start; Call_Constructor: // This line of code will not be executed. // The purpose of the code is to allow the compiler to generate the assembly code that calls the constructor. T(); Start: // The address of the line of code T() obtained by assembly char *p = (char *)&&Call_Constructor; // https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html // CALL rel32 void *ret = 0; char pos; char call = 0xe8; do { pos = *p; if (pos == call) { ret = p + 5 + (*(int *)(p + 1)); } } while (!ret && (++p)); return ret; } protected: std::map m_wrappers; }; } #endif // STUBEXT_H ukui-biometric-auth/tests/kt-test-utils/cpp-stub-ext/stub-shadow.cpp0000664000175000017500000000314715167732630024600 0ustar fengfeng/* * Author: Zhang Yu * Maintainer: Zhang Yu * * MIT License * * Copyright (c) 2020 Zhang Yu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "stub-shadow.h" namespace stub_ext { WrapperMap stub_wrappers; Wrapper::Wrapper() { } Wrapper::~Wrapper() { } void freeWrapper(Wrapper *wrapper) { if (!wrapper) return; for (auto iter = stub_wrappers.begin(); iter != stub_wrappers.end();) { if (iter->second == wrapper) iter = stub_wrappers.erase(iter); else ++iter; } delete wrapper; } } ukui-biometric-auth/tests/kt-test-utils/cpp-stub-ext/stub-shadow.h0000664000175000017500000001143415167732630024243 0ustar fengfeng #ifndef STUBSHADOW_H #define STUBSHADOW_H /* * Author: Zhang Yu * Maintainer: Zhang Yu * * MIT License * * Copyright (c) 2020 Zhang Yu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include namespace stub_ext { #define LAMDA_FUNCTION_TYPE decltype(&Lamda::operator()) class Wrapper { public: Wrapper(); virtual ~Wrapper(); }; typedef std::unordered_map WrapperMap; extern WrapperMap stub_wrappers; template class LamdaWrapper : public Wrapper { public: LamdaWrapper(Lamda func): Wrapper(),_func(func){} ~LamdaWrapper(){} Lamda _func; }; template struct VFLocator { }; template struct VFLocator { typedef Ret (*Func)(Obj*, Args...); }; template struct VFLocator { typedef Ret (*Func)(Obj*, Args...); }; template struct LamdaCaller { }; template struct LamdaCaller { template static Ret call(LamdaWrapper *wrapper, OrgArgs&&... args) { return wrapper->_func(std::forward(args)...); } }; template struct LamdaCaller { template static Ret call(LamdaWrapper *wrapper, OrgArgs&&... args) { return wrapper->_func(); } }; template struct FuncShadow { }; template struct FuncShadow { typedef Ret (*Shadow)(Args...); typedef Ret RetType; static Ret call(Args ...args) { Shadow shadow = &call; long id = (long)shadow; auto iter = stub_wrappers.find(id); assert(stub_wrappers.find(id) != stub_wrappers.end()); LamdaWrapper *wrapper = dynamic_cast *>(iter->second); return LamdaCaller::call(wrapper, args...); } }; template struct FuncShadow { typedef Ret (*Shadow)(Obj *,Args...); typedef Ret RetType; static Ret call(Obj *obj, Args ...args) { Shadow shadow = &call; long id = (long)shadow; auto iter = stub_wrappers.find(id); assert(stub_wrappers.find(id) != stub_wrappers.end()); LamdaWrapper *wrapper = dynamic_cast *>(iter->second); return LamdaCaller::call(wrapper, obj, args...); } }; template struct FuncShadow { typedef Ret (*Shadow)(Obj *,Args...); typedef Ret RetType; static Ret call(Obj *obj, Args ...args) { Shadow shadow = &call; long id = (long)shadow; auto iter = stub_wrappers.find(id); assert(stub_wrappers.find(id) != stub_wrappers.end()); LamdaWrapper *wrapper = dynamic_cast *>(iter->second); return LamdaCaller::call(wrapper, obj, args...); } }; template typename FuncShadow::Shadow depictShadow(Wrapper **wrapper, Func func, Lamda lamda) { *wrapper = new LamdaWrapper(lamda); typename FuncShadow::Shadow shadow = &FuncShadow::call; long id = (long)shadow; assert(stub_wrappers.find(id) == stub_wrappers.end()); stub_wrappers.insert(std::make_pair(id,*wrapper)); return shadow; } void freeWrapper(Wrapper *wrapper); } #endif // STUBSHADOW_H ukui-biometric-auth/tests/unit_test_loginoptionswidget/0000775000175000017500000000000015167732644022576 5ustar fengfengukui-biometric-auth/tests/unit_test_loginoptionswidget/CMakeLists.txt0000664000175000017500000000435715167732630025342 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(PkgConfig REQUIRED) find_package(Qt5 COMPONENTS Core Gui DBus Widgets Svg REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) find_package(OpenCV REQUIRED) pkg_check_modules(GIOUNIX2 REQUIRED gio-unix-2.0) pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") qt5_add_resources(polkit_SRCS ../../polkit-agent/assets.qrc) # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES main.cpp ../../bioauth/src/uniauthservice.cpp ../../bioauth/src/biotypes.cpp ../../bioauth/src/giodbus.cpp ../../bioauth/src/bioauth.cpp ../../bioauth/src/biodevices.cpp ../../bioauth/src/loginoptionswidget.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../bioauth/include/uniauthservice.h ../../bioauth/include/bioauth.h ../../bioauth/include/biodevices.h ../../bioauth/include/loginoptionswidget.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ../../bioauth/include ../../common ${GIOUNIX2_INCLUDE_DIRS} ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_loginoptionswidget ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_loginoptionswidget Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets Qt5::Svg ${OpenCV_LIBS} ${GIOUNIX2_LIBRARIES} ) # 链接 GTest 库 target_link_libraries(unit_test_loginoptionswidget GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_loginoptionswidget/main.cpp0000664000175000017500000003453715167732644024242 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include #include #include #include "../../bioauth/include/loginoptionswidget.h" // 假设这个头文件存在,并包含了BioAuth类的声明 TEST(LoginOptionsWidgetTest, init) { LoginOptionsWidget loginWidget; EXPECT_EQ(loginWidget.getLoginOptCount(),0); EXPECT_EQ(loginWidget.convertDeviceType(0),0); int nLoginOptType,nDrvId; loginWidget.getCurLoginOpt(nLoginOptType,nDrvId); loginWidget.getFirstDevInfo(); loginWidget.updateUIStatus(false); loginWidget.updateUIStatus(true); loginWidget.updateUkeyUIStatus(0); loginWidget.updateUkeyUIStatus(1); loginWidget.updateUkeyUIStatus(8); loginWidget.setUser(1000); loginWidget.setCurrentDevice(-1); loginWidget.setCurrentDevice("test"); loginWidget.setDeviceDisable(100,false); loginWidget.setDeviceDisable(100,true); loginWidget.isDeviceDisable(false); loginWidget.lockStatusChanged(false); loginWidget.lockStatusChanged(true); loginWidget.readDevicesInfo(); loginWidget.onIdentifyComplete(1000,true,0); loginWidget.onIdentifyComplete(1000,false,0); loginWidget.onIdentifyComplete(-1,true,0); loginWidget.onAuthFinished(); loginWidget.onStatusChanged(1000,"test"); loginWidget.onFrameWritten(1000); loginWidget.onUSBDeviceCountChange(0); loginWidget.onUSBDeviceCountChange(1); loginWidget.onOptionSelected(-1); loginWidget.onOptionSelected(0); loginWidget.onOptionSelected(1); loginWidget.setQRCodeMsg(""); loginWidget.setQRCodeMsg("test"); EXPECT_EQ(loginWidget.GetDefaultDevice(1000),""); EXPECT_EQ(loginWidget.GetDefaultDevice(1000,0),""); loginWidget.startAuth(nullptr,1000); loginWidget.stopAuth(); loginWidget.SetExtraInfo("test1","test2"); EXPECT_EQ(loginWidget.getHasUkeyOptions(),false); loginWidget.setSelectedPassword(); loginWidget.setAllDeviceDisable(true); loginWidget.setAllDeviceDisable(false); loginWidget.notifyOptionsChange(-1); loginWidget.notifyOptionsChange(0); loginWidget.notifyOptionsChange(1); loginWidget.optionSelected(LOGINOPT_TYPE_GENERAL_UKEY,nullptr); QImage image; loginWidget.updateImage(image); loginWidget.authComplete(1000,-1,-1); loginWidget.updateAuthMsg("test"); loginWidget.updateWndSize(0,100); loginWidget.initUI(); loginWidget.initConnections(); loginWidget.addOptionButton(LOGINOPT_TYPE_PASSWORD,0,"LOGINOPT_TYPE_PASSWORD"); loginWidget.addOptionButton(LOGINOPT_TYPE_GENERAL_UKEY,1,"LOGINOPT_TYPE_GENERAL_UKEY"); loginWidget.addOptionButton(LOGINOPT_TYPE_FACE,2,"LOGINOPT_TYPE_FACE"); loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERPRINT,3,"LOGINOPT_TYPE_FINGERPRINT"); loginWidget.addOptionButton(LOGINOPT_TYPE_IRIS,4,"LOGINOPT_TYPE_IRIS"); loginWidget.addOptionButton(LOGINOPT_TYPE_VOICEPRINT,5,"LOGINOPT_TYPE_VOICEPRINT"); loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERVEIN,6,"LOGINOPT_TYPE_FINGERVEIN"); loginWidget.addOptionButton(LOGINOPT_TYPE_QRCODE,7,"LOGINOPT_TYPE_QRCODE"); loginWidget.onOptionSelected(-1); loginWidget.onOptionSelected(0); loginWidget.onOptionSelected(1); loginWidget.clearOptionButtons(); loginWidget.updateOptionButtons(); loginWidget.startAuth_(); loginWidget.stopAuth(); QPixmap pix = QIcon::fromTheme("ukui-loading-0-symbolic").pixmap(24, 24); loginWidget.PixmapToRound(pix,32); QPixmap pix1; loginWidget.PixmapToRound(pix1,32); loginWidget.scaledPixmap(1024,768,"/usr/share/backgrounds/1-warty-final-ubuntukylin.jpg"); loginWidget.scaledPixmap(1024,768,"/usr/share/backgrounds/test-warty-final-ubuntukylin.jpg"); loginWidget.scaledPixmap(1024,768,"/usr/share/ukui-biometric/images/ukui-loginopt-face.svg"); loginWidget.scaledPixmap(1024,768,"/usr/share/ukui-biometric/images/FingerPrint.gif"); loginWidget.scaledPixmap(1024,768,"/usr/share/ukui-biometric/ukui-biometric.conf"); loginWidget.updatePixmap(); loginWidget.drawSymbolicColoredPixmap(pix,"white"); loginWidget.drawSymbolicColoredPixmap(pix,"blue"); loginWidget.drawSymbolicColoredPixmap(pix,"gray"); loginWidget.drawSymbolicColoredPixmap(pix,"black"); loginWidget.drawSymbolicColoredPixmap(pix,"red"); QImage img; QImage img1 = pix1.toImage(); loginWidget.setFaceImg(img,1); loginWidget.setFaceImg(img,2); loginWidget.setFaceImg(img,3); loginWidget.setFaceImg(img1,1); loginWidget.convertDeviceType(BIOTYPE_FINGERPRINT); loginWidget.convertDeviceType(BIOTYPE_FINGERVEIN); loginWidget.convertDeviceType(BIOTYPE_IRIS); loginWidget.convertDeviceType(BIOTYPE_FACE); loginWidget.convertDeviceType(BIOTYPE_VOICEPRINT); loginWidget.convertDeviceType(UniT_General_Ukey); loginWidget.convertDeviceType(UniT_Advanced_Ukey); loginWidget.convertDeviceType(REMOTE_QRCODE_TYPE); loginWidget.convertDeviceType(-1); } TEST(LoginOptionsWidgetTest, noProxy) { LoginOptionsWidget loginWidget; loginWidget.m_biomericProxy = nullptr; loginWidget.SetExtraInfo("test1","test2"); } // 模拟startAuth的调用 TEST(LoginOptionsWidgetTest, startAuth) { DeviceInfoPtr pDeviceInfo = std::make_shared(); pDeviceInfo->device_id = 100; pDeviceInfo->device_shortname = "TestDevice"; pDeviceInfo->device_fullname = "Test Device Full Name"; pDeviceInfo->driver_enable = 1; pDeviceInfo->device_available = 1; pDeviceInfo->biotype = BIOTYPE_FINGERPRINT; pDeviceInfo->stotype = 0; pDeviceInfo->eigtype = 0; pDeviceInfo->vertype = 0; pDeviceInfo->idtype = 0; pDeviceInfo->bustype = 0; pDeviceInfo->dev_status = 0; pDeviceInfo->ops_status = 0; LoginOptionsWidget loginWidget; loginWidget.onOptionSelected(-1); loginWidget.onOptionSelected(0); loginWidget.onOptionSelected(1); loginWidget.m_mapDevices[LOGINOPT_TYPE_FINGERPRINT].push_back(pDeviceInfo); loginWidget.setCurrentDevice("TestDevice"); loginWidget.setCurrentDevice(100); loginWidget.setCurrentDevice(pDeviceInfo); loginWidget.startAuth(pDeviceInfo,1000); loginWidget.m_isInAuth = true; loginWidget.stopAuth(); loginWidget.onStatusChanged(100,"this is test"); } // 模拟认证完成 TEST(LoginOptionsWidgetTest, onIdentifyComplete) { LoginOptionsWidget loginWidget; loginWidget.m_isStopped = false; loginWidget.onIdentifyComplete(-1,-1,-1); loginWidget.onIdentifyComplete(0,-1,-1); loginWidget.onIdentifyComplete(0,-1,1000); loginWidget.onIdentifyComplete(0,-1,200); loginWidget.onIdentifyComplete(-1,-1,-3); } //模拟device管理 TEST(LoginOptionsWidgetTest, testAllDevice) { DeviceInfoPtr pDeviceInfo = std::make_shared(); pDeviceInfo->device_id = 100; pDeviceInfo->device_shortname = "TestDevice"; pDeviceInfo->device_fullname = "Test Device Full Name"; pDeviceInfo->driver_enable = 1; pDeviceInfo->device_available = 1; pDeviceInfo->biotype = BIOTYPE_FINGERPRINT; pDeviceInfo->stotype = 0; pDeviceInfo->eigtype = 0; pDeviceInfo->vertype = 0; pDeviceInfo->idtype = 0; pDeviceInfo->bustype = 0; pDeviceInfo->dev_status = 0; pDeviceInfo->ops_status = 0; DeviceInfoPtr pDeviceInfo1 = std::make_shared(); pDeviceInfo1->device_id = 101; pDeviceInfo1->device_shortname = "TestDevice1"; pDeviceInfo1->device_fullname = "Test Device Full Name"; pDeviceInfo1->driver_enable = 1; pDeviceInfo1->device_available = 1; pDeviceInfo1->biotype = BIOTYPE_FINGERVEIN; pDeviceInfo1->stotype = 0; pDeviceInfo1->eigtype = 0; pDeviceInfo1->vertype = 0; pDeviceInfo1->idtype = 0; pDeviceInfo1->bustype = 0; pDeviceInfo1->dev_status = 0; pDeviceInfo1->ops_status = 0; DeviceInfoPtr pDeviceInfo2 = std::make_shared(); pDeviceInfo2->device_id = 102; pDeviceInfo2->device_shortname = "TestDevice2"; pDeviceInfo2->device_fullname = "Test Device Full Name"; pDeviceInfo2->driver_enable = 1; pDeviceInfo2->device_available = 1; pDeviceInfo2->biotype = BIOTYPE_IRIS; pDeviceInfo2->stotype = 0; pDeviceInfo2->eigtype = 0; pDeviceInfo2->vertype = 0; pDeviceInfo2->idtype = 0; pDeviceInfo2->bustype = 0; pDeviceInfo2->dev_status = 0; pDeviceInfo2->ops_status = 0; DeviceInfoPtr pDeviceInfo3 = std::make_shared(); pDeviceInfo3->device_id = 103; pDeviceInfo3->device_shortname = "TestDevice3"; pDeviceInfo3->device_fullname = "Test Device Full Name"; pDeviceInfo3->driver_enable = 1; pDeviceInfo3->device_available = 1; pDeviceInfo3->biotype = BIOTYPE_FACE; pDeviceInfo3->stotype = 0; pDeviceInfo3->eigtype = 0; pDeviceInfo3->vertype = 0; pDeviceInfo3->idtype = 0; pDeviceInfo3->bustype = 0; pDeviceInfo3->dev_status = 0; pDeviceInfo3->ops_status = 0; DeviceInfoPtr pDeviceInfo4 = std::make_shared(); pDeviceInfo4->device_id = 104; pDeviceInfo4->device_shortname = "TestDevice4"; pDeviceInfo4->device_fullname = "Test Device Full Name"; pDeviceInfo4->driver_enable = 1; pDeviceInfo4->device_available = 1; pDeviceInfo4->biotype = BIOTYPE_VOICEPRINT; pDeviceInfo4->stotype = 0; pDeviceInfo4->eigtype = 0; pDeviceInfo4->vertype = 0; pDeviceInfo4->idtype = 0; pDeviceInfo4->bustype = 0; pDeviceInfo4->dev_status = 0; pDeviceInfo4->ops_status = 0; DeviceInfoPtr pDeviceInfo5 = std::make_shared(); pDeviceInfo5->device_id = 105; pDeviceInfo5->device_shortname = "TestDevice5"; pDeviceInfo5->device_fullname = "Test Device Full Name"; pDeviceInfo5->driver_enable = 1; pDeviceInfo5->device_available = 1; pDeviceInfo5->biotype = 6; pDeviceInfo5->stotype = 0; pDeviceInfo5->eigtype = 0; pDeviceInfo5->vertype = 0; pDeviceInfo5->idtype = 0; pDeviceInfo5->bustype = 0; pDeviceInfo5->dev_status = 0; pDeviceInfo5->ops_status = 0; DeviceInfoPtr pDeviceInfo6 = std::make_shared(); pDeviceInfo6->device_id = 106; pDeviceInfo6->device_shortname = "TestDevice6"; pDeviceInfo6->device_fullname = "Test Device Full Name"; pDeviceInfo6->driver_enable = 1; pDeviceInfo6->device_available = 1; pDeviceInfo6->biotype = 6; pDeviceInfo6->stotype = 0; pDeviceInfo6->eigtype = 0; pDeviceInfo6->vertype = 0; pDeviceInfo6->idtype = 0; pDeviceInfo6->bustype = 0; pDeviceInfo6->dev_status = 0; pDeviceInfo6->ops_status = 0; DeviceInfoPtr pDeviceInfo7 = std::make_shared(); pDeviceInfo7->device_id = 107; pDeviceInfo7->device_shortname = "TestDevice7"; pDeviceInfo7->device_fullname = "Test Device Full Name"; pDeviceInfo7->driver_enable = 1; pDeviceInfo7->device_available = 1; pDeviceInfo7->biotype = 7; pDeviceInfo7->stotype = 0; pDeviceInfo7->eigtype = 0; pDeviceInfo7->vertype = 0; pDeviceInfo7->idtype = 0; pDeviceInfo7->bustype = 0; pDeviceInfo7->dev_status = 0; pDeviceInfo7->ops_status = 0; DeviceInfoPtr pDeviceInfo8 = std::make_shared(); pDeviceInfo8->device_id = 108; pDeviceInfo8->device_shortname = "TestDevice8"; pDeviceInfo8->device_fullname = "Test Device Full Name"; pDeviceInfo8->driver_enable = 1; pDeviceInfo8->device_available = 1; pDeviceInfo8->biotype = 8; pDeviceInfo8->stotype = 0; pDeviceInfo8->eigtype = 0; pDeviceInfo8->vertype = 0; pDeviceInfo8->idtype = 0; pDeviceInfo8->bustype = 0; pDeviceInfo8->dev_status = 0; pDeviceInfo8->ops_status = 0; LoginOptionsWidget loginWidget; loginWidget.m_mapDevices[0].push_back(pDeviceInfo); loginWidget.m_mapDevices[1].push_back(pDeviceInfo1); loginWidget.m_mapDevices[2].push_back(pDeviceInfo2); loginWidget.m_mapDevices[3].push_back(pDeviceInfo2); loginWidget.m_mapDevices[4].push_back(pDeviceInfo4); loginWidget.m_mapDevices[5].push_back(pDeviceInfo5); loginWidget.m_mapDevices[6].push_back(pDeviceInfo6); loginWidget.m_mapDevices[7].push_back(pDeviceInfo7); loginWidget.m_mapDevices[8].push_back(pDeviceInfo8); loginWidget.addOptionButton(LOGINOPT_TYPE_PASSWORD,0,"LOGINOPT_TYPE_PASSWORD"); loginWidget.addOptionButton(LOGINOPT_TYPE_PASSWORD,0,"LOGINOPT_TYPE_PASSWORD"); loginWidget.addOptionButton(LOGINOPT_TYPE_GENERAL_UKEY,1,"LOGINOPT_TYPE_GENERAL_UKEY"); loginWidget.addOptionButton(LOGINOPT_TYPE_FACE,2,"LOGINOPT_TYPE_FACE"); loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERPRINT,3,"LOGINOPT_TYPE_FINGERPRINT"); loginWidget.addOptionButton(LOGINOPT_TYPE_IRIS,4,"LOGINOPT_TYPE_IRIS"); loginWidget.addOptionButton(LOGINOPT_TYPE_VOICEPRINT,5,"LOGINOPT_TYPE_VOICEPRINT"); loginWidget.addOptionButton(LOGINOPT_TYPE_FINGERVEIN,6,"LOGINOPT_TYPE_FINGERVEIN"); loginWidget.addOptionButton(LOGINOPT_TYPE_QRCODE,7,"LOGINOPT_TYPE_QRCODE"); loginWidget.setCurrentDevice(100); int nLoginOptType,nDrvId; loginWidget.getCurLoginOpt(nLoginOptType,nDrvId); loginWidget.getFirstDevInfo(); loginWidget.updateOptionButtons(); loginWidget.setSelectedPassword(); loginWidget.startAuth(pDeviceInfo,1000); loginWidget.startAuth(pDeviceInfo1,1000); loginWidget.startAuth(pDeviceInfo2,1000); loginWidget.startAuth(pDeviceInfo3,1000); loginWidget.startAuth(pDeviceInfo4,1000); loginWidget.startAuth(pDeviceInfo5,1000); loginWidget.startAuth(pDeviceInfo6,1000); loginWidget.startAuth(pDeviceInfo7,1000); loginWidget.startAuth(pDeviceInfo8,1000); } // 创建一个全局的QApplication对象,因为Qt测试通常需要一个事件循环 int main(int argc, char **argv) { QApplication a(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_modebutton/0000775000175000017500000000000015167732644021026 5ustar fengfengukui-biometric-auth/tests/unit_test_modebutton/CMakeLists.txt0000664000175000017500000000327015167732644023570 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(QGS REQUIRED gsettings-qt6) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../polkit-agent/src/modeButton.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../polkit-agent/src/modeButton.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ${QGS_INCLUDE_DIRS} ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_modebutton ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_modebutton Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets ${QGS_LIBRARIES} ) # 链接 GTest 库 target_link_libraries(unit_test_modebutton GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_modebutton/main.cpp0000664000175000017500000000722515167732644022464 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include "../../polkit-agent/src/modeButton.h" // Test fixture for ModeButton class ModeButtonTest : public ::testing::Test { protected: }; TEST_F(ModeButtonTest, TestDefaultConstructor) { ModeButton button(nullptr); EXPECT_EQ(button.isShowPwd(), false); EXPECT_EQ(button.size(), QSize(24, 24)); } TEST_F(ModeButtonTest, TestIconConstructor) { ModeButton button("testIcon", nullptr); // Since we can't directly assert the icon, we assume the constructor sets up the internal state correctly EXPECT_EQ(button.size(), QSize(24, 24)); // Further checks would involve mocking QIcon::fromTheme and verifying interactions } TEST_F(ModeButtonTest, TestShowPasswordToggle) { ModeButton button(nullptr); // Mock QGSettings to return a theme name that is not dark or black button.initStyleTheme(); // Initially, pwdShow should be false EXPECT_EQ(button.isShowPwd(), false); // Simulate a click event emit button.clicked(); // Now pwdShow should be true EXPECT_EQ(button.isShowPwd(), true); // Simulate another click event emit button.clicked(); // Now pwdShow should be false again EXPECT_EQ(button.isShowPwd(), false); } TEST_F(ModeButtonTest, TestHoverEffect) { ModeButton button(nullptr); // Mock QGSettings to return a theme name that is not dark or black button.initStyleTheme(); // Simulate entering the hover state QEvent enterEvent(QEvent::Enter); QApplication::sendEvent(&button, &enterEvent); // Verify the icon is set to white (or appropriate hover color) // This would involve checking the internal state or mocking QIcon::pixmap and QPixmap::fromImage // Since we can't directly access the icon, we assume setModeIcon handles it correctly // Simulate leaving the hover state QEvent leaveEvent(QEvent::Leave); QApplication::sendEvent(&button, &leaveEvent); // Verify the icon is set back to gray (or appropriate non-hover color) // Similarly, we assume setModeIcon handles it correctly } TEST_F(ModeButtonTest, TestThemeChange) { ModeButton button(nullptr); button.initStyleTheme(); button.setModeIcon(); button.m_styleSettings->changed("styleName"); QPixmap pixmap = QIcon::fromTheme("ukui-eye-display-symbolic").pixmap(24,24); pixmap = button.drawSymbolicColoredPixmap(pixmap, "black"); pixmap = button.drawSymbolicColoredPixmap(pixmap, "blue"); pixmap = button.drawSymbolicColoredPixmap(pixmap, "gray"); pixmap = button.drawSymbolicColoredPixmap(pixmap, "white"); pixmap = button.drawSymbolicColoredPixmap(pixmap, "red"); button.m_strThemeName = "ukui-dark"; button.setModeIcon(); button.m_strThemeName = "ukui-black"; button.setModeIcon(); } int main(int argc, char **argv) { QApplication app(argc, argv);; ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_biodevices/0000775000175000017500000000000015167732644020762 5ustar fengfengukui-biometric-auth/tests/unit_test_biodevices/CMakeLists.txt0000664000175000017500000000423215167732630023516 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(PkgConfig REQUIRED) find_package(Qt5 COMPONENTS Core Gui DBus Widgets Svg REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) find_package(OpenCV REQUIRED) pkg_check_modules(GIOUNIX2 REQUIRED gio-unix-2.0) pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES main.cpp ../../bioauth/src/uniauthservice.cpp ../../bioauth/src/biotypes.cpp ../../bioauth/src/giodbus.cpp ../../bioauth/src/bioauth.cpp ../../bioauth/src/biodevices.cpp ../../bioauth/src/loginoptionswidget.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../bioauth/include/uniauthservice.h ../../bioauth/include/bioauth.h ../../bioauth/include/biodevices.h ../../bioauth/include/loginoptionswidget.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ../../bioauth/include ../../common ${GIOUNIX2_INCLUDE_DIRS} ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_biodevices ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_biodevices Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets Qt5::Svg ${OpenCV_LIBS} ${GIOUNIX2_LIBRARIES} ) # 链接 GTest 库 target_link_libraries(unit_test_biodevices GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_biodevices/main.cpp0000664000175000017500000001021515167732644022411 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include #include #include "../../bioauth/include/biodevices.h" // 假设这个头文件存在,并包含了BioAuth类的声明 TEST(BioDevicesTest, init) { BioDevices devices; EXPECT_EQ(devices.count(),0); devices.setUId(1000); devices.getAllDevices(); devices.getUserDevices(1000); devices.getDevices(0); devices.getDefaultDevice(1000); devices.getDefaultDevice(1000,0); devices.GetLastDevice("kylin"); devices.SetLastDevice("kylin",100); devices.SetLastDevice("kylin",-1); devices.SetLastDevice("testx",100); devices.findDevice("testDevice"); devices.findDevice(100); devices.getFirstDevice(1000); devices.GetDevList(); devices.getFeatureCount(1000,0,-1); devices.bioTypeToString_tr(0); devices.bioTypeToString_tr(1); devices.bioTypeToString_tr(2); devices.bioTypeToString_tr(3); devices.bioTypeToString_tr(4); devices.bioTypeToString_tr(5); devices.bioTypeToString_tr(6); devices.bioTypeToString_tr(7); devices.bioTypeToString_tr(8); devices.setIsShowHotPlug(true); devices.setIsShowHotPlug(false); devices.GetUserDevFeatureCount(1000,100); devices.GetUserDevCount(1000); devices.GetUserFeatures(1000); devices.getUseFirstDevice(); devices.getFailedTimes(); devices.GetHiddenSwitchButton(); devices.GetQRCodeEnable(); devices.GetBioAuthEnable(); devices.getAllDefDevices(); devices.UpdateStatus(100); devices.UpdateStatus(-1); devices.GetBioAuthEnable(1000); devices.GetDirveIsIdle(100); devices.recordAuthDrive("test",100,true); devices.recordAuthDrive("test",100,false); devices.onUSBDeviceHotPlug(10,-1,10); devices.onUSBDeviceHotPlug(10,1,10); devices.m_uniAuthService = nullptr; devices.setUId(1000); devices.getAllDevices(); devices.getUserDevices(1000); devices.getDevices(0); devices.getDefaultDevice(1000); devices.getDefaultDevice(1000,0); devices.GetLastDevice("kylin"); devices.SetLastDevice("kylin",100); devices.SetLastDevice("kylin",-1); devices.findDevice("testDevice"); devices.findDevice(100); devices.getFirstDevice(1000); devices.GetDevList(); devices.getFeatureCount(1000,0,-1); devices.bioTypeToString_tr(0); devices.bioTypeToString_tr(1); devices.bioTypeToString_tr(2); devices.bioTypeToString_tr(3); devices.bioTypeToString_tr(4); devices.bioTypeToString_tr(5); devices.bioTypeToString_tr(6); devices.bioTypeToString_tr(7); devices.bioTypeToString_tr(8); devices.setIsShowHotPlug(true); devices.setIsShowHotPlug(false); devices.GetUserDevFeatureCount(1000,100); devices.GetUserDevCount(1000); devices.GetUserFeatures(1000); devices.getUseFirstDevice(); devices.getFailedTimes(); devices.GetHiddenSwitchButton(); devices.GetQRCodeEnable(); devices.GetBioAuthEnable(); devices.getAllDefDevices(); devices.UpdateStatus(100); devices.UpdateStatus(-1); devices.GetBioAuthEnable(1000); devices.GetDirveIsIdle(100); devices.recordAuthDrive("test",100,true); devices.recordAuthDrive("test",100,false); devices.onUSBDeviceHotPlug(10,-1,10); devices.onUSBDeviceHotPlug(10,1,10); } // 创建一个全局的QApplication对象,因为Qt测试通常需要一个事件循环 int main(int argc, char **argv) { QApplication a(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_pam_tally/0000775000175000017500000000000015167732644020630 5ustar fengfengukui-biometric-auth/tests/unit_test_pam_tally/CMakeLists.txt0000664000175000017500000000312515167732630023364 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../polkit-agent/src/pam-tally.c main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../polkit-agent/src/pam-tally.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_pam_tally ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_pam_tally Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets ) # 链接 GTest 库 target_link_libraries(unit_test_pam_tally GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_pam_tally/main.cpp0000664000175000017500000001034015167732644022256 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include "../../polkit-agent/src/pam-tally.h" #include #include #include #include #include #include #include #define CONFIG_FILE "/usr/share/lightdm/lightdm.conf.d/96-kylin-setting.conf" // 辅助函数,用于模拟配置文件内容 void write_config_file(const char* content) { FILE* file = fopen(CONFIG_FILE, "w"); if (file) { fputs(content, file); fclose(file); } else { perror("Failed to open config file for writing"); exit(EXIT_FAILURE); } } // 辅助函数,用于清理共享内存 void cleanup_shm() { } class PamTallyTest : public ::testing::Test { protected: void SetUp() override { // 在每个测试用例之前运行 cleanup_shm(); // 确保每次测试前清理共享内存 } void TearDown() override { // 在每个测试用例之后运行 cleanup_shm(); // 确保每次测试后清理共享内存 } }; TEST_F(PamTallyTest, PamTallyInit) { // 测试pam_tally_init函数 write_config_file("open-other-authentication=0\n"); // 确保配置关闭其他认证 // 临时修改/etc/pam.d/common-auth文件以进行测试 //const char* auth_file_content = "auth required pam_deny.so deny=3 unlock_time=600 root_unlock_time=1800\n"; //FILE* auth_file = fopen("/etc/pam.d/common-auth", "w"); //if (auth_file) { // fputs(auth_file_content, auth_file); // fclose(auth_file); //} else { // perror("Failed to open auth file for writing"); // exit(EXIT_FAILURE); //} int result = pam_tally_init(); EXPECT_EQ(result, 1); // 预期初始化成功 } TEST_F(PamTallyTest, PamTallyIsCanUnlock) { // 测试pam_tally_is_canUnlock函数 pam_tally_init(); // 初始化pam_tally并设置解锁时间为600秒 pam_tally_add_failed(); // 添加一次失败,不足以达到失败次数上限 EXPECT_EQ(pam_tally_is_canUnlock(), 1); // 预期可以解锁,因为失败次数未达到上限 // 添加足够多的失败次数以达到上限,并检查是否可以解锁 for (int i = 0; i < 2; ++i) { pam_tally_add_failed(); } time_t start_time = time(NULL); EXPECT_EQ(pam_tally_is_canUnlock(), 0); // 预期不能解锁,因为失败次数已达到上限且未过解锁时间 // 等待超过解锁时间后,再次检查是否可以解锁 sleep(601); // 假设解锁时间为600秒,这里等待601秒以确保超过解锁时间 EXPECT_EQ(pam_tally_is_canUnlock(), 1); // 预期现在可以解锁,因为已经超过解锁时间 } TEST_F(PamTallyTest, PamTallyUnlockTime) { // 测试pam_tally_is_canUnlock函数 pam_tally_init(); // 初始化pam_tally并设置解锁时间为600秒 pam_tally_add_failed(); // 添加一次失败,不足以达到失败次数上限 int failed_count = 0; int time_left = 0; int deny = 0; int fail_time = 0; int unlock_time = 0; pam_tally_unlock_time_left(1000, &failed_count, &time_left, &deny, &fail_time, &unlock_time); EXPECT_EQ(failed_count, 0); EXPECT_EQ(time_left, 0); EXPECT_EQ(deny, 0); EXPECT_EQ(fail_time, 0); EXPECT_EQ(unlock_time, 0); pam_tally_root_unlock_time_left(&failed_count, &time_left, &deny, &fail_time, &unlock_time); EXPECT_EQ(failed_count, 0); EXPECT_EQ(time_left, 0); EXPECT_EQ(deny, 0); EXPECT_EQ(fail_time, 0); EXPECT_EQ(unlock_time, 0); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_servicemanager/0000775000175000017500000000000015167732644021641 5ustar fengfengukui-biometric-auth/tests/unit_test_servicemanager/CMakeLists.txt0000664000175000017500000000313515167732631024377 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../uniauth-backend/src/servicemanager.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../uniauth-backend/src/servicemanager.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_servicemanager ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_servicemanager Qt5::Core Qt5::Gui Qt5::DBus ) # 链接 GTest 库 target_link_libraries(unit_test_servicemanager GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_servicemanager/main.cpp0000664000175000017500000000321115167732644023266 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include "../../uniauth-backend/src/servicemanager.h" #include #include #define SERVICE "biometric-authentication.service" #define DBUS_SERVICE "org.ukui.Biometric" #define DBUS_PATH "/org/ukui/Biometric" #define DBUS_INTERFACE "org.ukui.Biometric" #define FD_DBUS_SERVICE "org.freedesktop.DBus" #define FD_DBUS_PATH "/org/freedesktop/DBus" #define FD_DBUS_INTERFACE "org.freedesktop.DBus" // gtest 测试用例 TEST(ServiceManagerTest, SerializationAndDeserialization) { ServiceManager *sm = ServiceManager::instance(); sm->connectToService(); sm->serviceStatusChanged(true); sm->serviceStatusChanged(false); sm->dbusNameOwnerChanged(DBUS_SERVICE,DBUS_SERVICE,DBUS_SERVICE); sm->onDBusNameOwnerChanged(DBUS_SERVICE,DBUS_SERVICE,DBUS_SERVICE); sm->serviceExists(); } int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_sessionmanager/0000775000175000017500000000000015167732644021664 5ustar fengfengukui-biometric-auth/tests/unit_test_sessionmanager/CMakeLists.txt0000664000175000017500000000316015167732631024420 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../polkit-agent/src/sessionmanager.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../polkit-agent/src/sessionmanager.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_sessionmanager ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_sessionmanager Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets ) # 链接 GTest 库 target_link_libraries(unit_test_sessionmanager GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_sessionmanager/main.cpp0000664000175000017500000000270615167732644023321 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ // sessionmanager_test.cpp #include #include #include #include #include #include #include #include "../../polkit-agent/src/sessionmanager.h" // Test fixture for SessionManager class SessionManagerTest : public ::testing::Test { protected: void SetUp() override { sessionManager = new SessionManager(); } void TearDown() override { delete sessionManager; } SessionManager* sessionManager; }; TEST_F(SessionManagerTest, testSessionManagerTest) { EXPECT_TRUE(sessionManager != nullptr); } int main(int argc, char **argv) { QCoreApplication app(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_common/0000775000175000017500000000000015167732644020136 5ustar fengfengukui-biometric-auth/tests/unit_test_common/CMakeLists.txt0000664000175000017500000000311715167732630022673 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../common/generic.cpp main.cpp unit_test_common.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../common/generic.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_common ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_common Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets ) # 链接 GTest 库 target_link_libraries(unit_test_common GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_common/main.cpp0000664000175000017500000000156115167732644021571 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include int main(int argc, char **argv) { QGuiApplication a(argc, argv); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/unit_test_common/unit_test_common.cpp0000664000175000017500000000227515167732644024236 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include "../../common/generic.h" #include "stubext.h" using namespace stub_ext; bool enableDebug = true; QString logPrefix = "[test]:"; class GenericTest : public testing::Test { protected: }; TEST_F(GenericTest, outputMessage) { qInstallMessageHandler(outputMessage); qDebug()<<"test1"; qWarning()<<"test2"; qInfo()<<"test3"; qCritical()<<"test4"; enableDebug = false; qDebug()<<"test5"; } ukui-biometric-auth/tests/unit_test_users/0000775000175000017500000000000015167732644020007 5ustar fengfengukui-biometric-auth/tests/unit_test_users/CMakeLists.txt0000664000175000017500000000310315167732631022540 0ustar fengfeng# CMake 最低版本要求 cmake_minimum_required(VERSION 3.10) find_package(Qt5 COMPONENTS Core Gui DBus Widgets REQUIRED) find_package(PkgConfig REQUIRED) # 包含 GTest 库和 pthread 库 find_package(GTest REQUIRED) find_package(Threads REQUIRED) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 开启代码覆盖率相关编译选项(对应QMAKE_LFLAGS和QMAKE_CXXFLAGS中代码覆盖率相关设置) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage --coverage -fno-inline -fno-access-control") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage") # 定义源文件列表,对应原来的SOURCES变量 set(SOURCES ../../polkit-agent/src/users.cpp main.cpp ) # 定义头文件列表,对应原来的HEADERS变量 set(HEADERS ../../polkit-agent/src/users.h ) # 包含头文件的路径设置,对应原来的INCLUDEPATH变量 include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub ${CMAKE_CURRENT_SOURCE_DIR}/../kt-test-utils/cpp-stub-ext ) # 使用qt5_wrap_cpp生成元对象代码相关的源文件 qt5_wrap_cpp(MOC_SOURCES ${HEADERS}) # 添加可执行文件或库目标,将元对象代码源文件一起添加进去 add_executable(unit_test_users ${SOURCES} ${MOC_SOURCES}) # 链接Qt相关的库 target_link_libraries(unit_test_users Qt5::Core Qt5::Gui Qt5::DBus Qt5::Widgets ) # 链接 GTest 库 target_link_libraries(unit_test_users GTest::GTest GTest::Main Threads::Threads ) ukui-biometric-auth/tests/unit_test_users/main.cpp0000664000175000017500000000652115167732644021443 0ustar fengfeng/* * Copyright (C) 2024 KylinSoftCo., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include "../../polkit-agent/src/users.h" #include #include #include #include #include #include #include class UsersTest : public ::testing::Test { protected: void SetUp() override { users = new Users(nullptr); } void TearDown() override { delete users; } Users *users; }; TEST_F(UsersTest, testGetUsers) { QList userList = users->getUsers(); EXPECT_EQ(userList.size(), 0); // Initially, the list should be empty // Load users should populate the list users->loadUsers(); userList = users->getUsers(); EXPECT_EQ(userList.size(), 2); // After loading, we expect 2 users EXPECT_EQ(userList[0].name, QString("testuser")); EXPECT_EQ(userList[0].uid, quint64(1000)); EXPECT_EQ(userList[1].name, QString("")); // The second user might not be fully populated in this mock } TEST_F(UsersTest, testGetUserByName) { users->loadUsers(); UserItem user = users->getUserByName("testuser"); EXPECT_EQ(user.name, QString("testuser")); EXPECT_EQ(user.realName, QString("Test User")); EXPECT_EQ(user.uid, quint64(1000)); user = users->getUserByName("nonexistent"); EXPECT_EQ(user.name, QString("nonexistent")); EXPECT_EQ(user.uid, ::getuid()); // Fallback uid should be the current uid user = users->getUserByName("root"); user = users->getUserByName("kylin"); qDebug()<getDefaultIcon(); EXPECT_EQ(defaultIcon, QString(":/image/assets/iconFace.png")); } TEST_F(UsersTest, testOnUserAddedAndDeleted) { // Set up a temporary directory and file to test icon loading QTemporaryDir tempDir; QFile tempFile(tempDir.filePath("icon.png")); tempFile.open(QIODevice::WriteOnly); tempFile.close(); // Load users users->loadUsers(); QList userList = users->getUsers(); EXPECT_EQ(userList.size(), 2); // Emit userAdded signal (simulate DBus signal) QDBusObjectPath path("/user/newuser"); QMetaObject::invokeMethod(users, "onUserAdded", Q_ARG(QDBusObjectPath, path)); userList = users->getUsers(); EXPECT_EQ(userList.size(), 3); // Now we should have 3 users // Emit userDeleted signal (simulate DBus signal) QMetaObject::invokeMethod(users, "onUserDeleted", Q_ARG(QDBusObjectPath, path)); userList = users->getUsers(); EXPECT_EQ(userList.size(), 2); // Back to 2 users } int main(int argc, char **argv) { QCoreApplication app(argc, argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-biometric-auth/tests/auto_test.sh0000664000175000017500000000303515167732644017114 0ustar fengfeng#!/bin/bash # 设置退出脚本当命令失败时 (非零退出状态) #set -e # 函数:运行单元测试 run_unit_tests() { local pattern="unit_test_*" # 遍历所有匹配模式的目录 for dir in $pattern; do if [ -d "$dir" ] && [ -x "$dir/$(basename "$dir")" ]; then echo "Running tests in $dir..." # 执行单元测试 (cd "$dir" && "./$(basename "$dir")") # 收集代码覆盖率数据 echo "Collecting coverage data..." (cd "$dir" && (find ./ -name '*.o' | xargs gcov --preserve-paths)) else echo "Skipping non-existent or non-executable directory: $dir, $dir/$(basename "$dir")" fi done } # 上传 result.zip 到平台 URL=$1 upload_result() { echo "current pwd : $(pwd)" # 收集覆盖率信息 lcov -d . -c -o r.info # 删除不需要的文件或路径 lcov -r r.info "$(pwd)/unit_test_*" "$(pwd)/../registeredSession/universalinterface.cpp" "/usr/include/*" "/opt/*" -o coverage.info # 生成html覆盖率报告 genhtml "$(pwd)/coverage.info" -o result # 打包 zip -r result.zip result # 上传平台 curl --insecure -X POST -F "file=@/$(pwd)/result.zip" -F "package=ukui-control-center" -F "username=hesisheng" $URL echo "all parameter : $@" } # 编译项目 echo "Compiling the project..." cmake . && make # 运行各个单元测试 echo "Running unit tests..." run_unit_tests # 上传到平台 #upload_result echo "All tests have been run successfully, and coverage data has been collected." ukui-biometric-auth/readme.txt0000664000175000017500000000044515167732630015402 0ustar fengfengbioctl status 获取生物特征总开关状态 bioctl status greeter|screensaver|polkit|sudo|su|login 获取应用开关状态 bioctl enable|disable 打开|关闭 生物特征总开关 bioctl enable|disable greeter|screensaver|polkit|sudo|su|login 打开|关闭 应用生物特征开关

HDֈI"'|F"rqxc> |IENDB`ukui-biometric-auth/images/Other/12.png0000664000175000017500000000337715167732630016671 0ustar fengfengPNG  IHDRbbIDATx흿nGƿ? MO4JWP&6RDUҺI-.q4{=z B2909VPn^ojP59W{%{Ư QVpPX58` g=5+sCSyI ! s6 + F FX7:{wB_WL#8>ywX/'kyY`5[suA ڮmY 0rDަ> o~ϲrL:IڦAR٦eF`cʵmpCi5ײmPL`(m @Zu0m>05_WܿyrN0 iL[YPZK^T >Cc1 cL״{i+4Uߙvmu&C`xfK`g3A9cke0 8CXVʼn0NR52k(lmGNȴ/ 1:YMG5?4CjA[p-(vi͎6qxK]4P ֵ|UW5]of`iղ F vym?Ld^sE9򎀌3N]:(D?>u3\/gVFKI~7D "D% JA (AQD "D% JA (AQD "D% JA (AQD "D% JA (AQD "D% JA (AQD "D% JA (AQ"5W<̫Y=6Tׇna 3W#̣|$ջYR<\w+J`+${Z[1!Ygp&{3u=ck@9,;!\ fS lt= X<9>(gKj8GxߛvAѵVQmGsܳ܏YQ3q{`Y>gY~'U'́\b1^`9Z 3#Y5mɽvs {ܓMLY|Xoڳ${`'L1KX}ϋhW0|nDk3;[xߨ>6rV:ڽѿ=g,\k%= %%P[ 3 6)raD~A/۠,-w.U /?6c4Aj:׺."}*:W:g9;lX Ȯv׸0hh-}gvϵ~@D4xE>|}:f zm/ >^ bږ#-:g|P\k P@i?'9 Da+Y0 ._vio[8#>g3ž*1F dH~SMcjFY/}V5ݞ*4{G_' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰' N (@8QpD‰' Nv}4NR,஻ێrmFT/rY抠zG r\иXͨuR3Qm )#5WATʨ:@Pl5v[6(lSmaX^&l3ʆ%Wg!նC,^F'"2BY,j96%gdהT!/K߻45kF溺p ~Hdtγ[ЇWf 7(gVqk_ڞ`Ӗ\%`kgSRIc`UNF7e֛w$!-HZ+PS59I8P˾tCO[ a"!L$0&DBH a6slܔNғfiW)_0&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBxߢ~;$Od/t&DBH a"!L$0`S;`UOmWpUo^4L_I#.AFj㮔 8`Vq6ؒ4-f:tǁ~{Rx˔'j$aIENDB`ukui-biometric-auth/images/Other/13.png0000664000175000017500000000121515167732630016657 0ustar fengfengPNG  IHDRbbTIDATx1nAoVAAN Bc: uLKkܤEimerGYA$QoS`jM@C k=El%0&DBH a"!L$׍ p];I2\_M6DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH}c&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH.7M'L' a"!L$0&DBH!5b~yqQ?U\֛W/LegQWJׅ90 6lϸp^lIC iqsݴX6ېy]HoD+9|IENDB`ukui-biometric-auth/images/Other/17.png0000664000175000017500000000121515167732630016663 0ustar fengfengPNG  IHDRbbTIDATx1nAoVAAN Bc: uLKkܤEimerGYA$QoS`jM@C k=El%0&DBH a"!L$׍ p];I2\_M6DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH}c&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH.7M'L' a"!L$0&DBH!5b~yqQ?U\֛W/LegQWJׅ90 6lϸp^lIC iqsݴX6ېy]HoD+9|IENDB`ukui-biometric-auth/images/Other/11.png0000664000175000017500000000372415167732630016664 0ustar fengfengPNG  IHDRbbIDATx흿EƿYdC@e&9^b~7'N""HUE;m~׳ZIwW55sjԿQT`$"'"XD~.p-v},"'>↬7HD^azovIs>3͓ZVQxC-*w=1zD^aXHM^x0̵xgSYږi. CKBXGѨq(֓X߉}-0 EFh݆ #` kڵB` Xfb{Wޙ}&"2Svb*/2pSO_JB ۦ;jۛ&x^e =Uj!Dd"E)~D6* 2Q LT@d"D}rM]EA=}jNlk\4Ϥ6y&5D gbS;v}vvTF]*51:Ii7w2`kzwvR.gd KW) }7l&vF5g[,m[pTH\޵SforrۓݦmOsK{3Tahݲl ƠO ݜ11,9YӾ8;7>Iu]DkxޏCv:;caV) HP$}^[Xw\5) ~';<3LN fF}^Gk=N_1uw=Bb %SGi<{|lGp(m<:ȼ-āNf xLiGAXs븥w27Id什P) MSTUBA>I=b;iV:8gxnӷ͙W\pX9|r`2MPԈB|a NbkWvKjhx~}ov6@X*jP#3Mh)\m%.7ntO “Ge%R瘼ϰ5'x>4.n$T#2Q LT@d"DD&* 2Q LT@dZAGrR9ʿID&* 2Q LT@d"D'x~0P[j x@9f_9AK yl߯Bx;7EX!< ș A"rR7=;́6W;녈 ʣoS`jM@C k=El%0&DBH a"!L$׍ p];I2\_M6DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH}c&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH.7M'L' a"!L$0&DBH!5b~yqQ?U\֛W/LegQWJׅ90 6lϸp^lIC iqsݴX6ېy]HoD+9|IENDB`ukui-biometric-auth/images/Other/18.png0000664000175000017500000000121515167732630016664 0ustar fengfengPNG  IHDRbbTIDATx1nAoVAAN Bc: uLKkܤEimerGYA$QoS`jM@C k=El%0&DBH a"!L$׍ p];I2\_M6DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH}c&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH.7M'L' a"!L$0&DBH!5b~yqQ?U\֛W/LegQWJׅ90 6lϸp^lIC iqsݴX6ېy]HoD+9|IENDB`ukui-biometric-auth/images/Other/05.png0000664000175000017500000000330215167732630016657 0ustar fengfengPNG  IHDRbbIDATx흽nW%"p i ݤӦ@zq6@JZ7 S;hvER290g8 D@D,cDx8i\A pB0773=O'; +R~.":ԧ#G az~\D ~f:'zm")AQD "D% JAl{=*TF:-ۚmh FƵ`15PmWpQ=sm4x '8 opF9X:T3΁g6Smm-:vz 7 r8I4"l0K_Զ`Z!S"7Ӫ{0lrJ> j}Y時h`SC~{NmCxvC綷MS7祔D)ED$ԓ殨2Ma (AQD "D% JA (AQD "D% JA (AQD "D% JA (AQD "D% JA (AQD "D% JA (AQD "Ss\ǯ:Ϧ>>GU=nïk/4 ѥ_: dvs; 9iP3Z -lk3YىZΨNfjXt2Lq`OD >;y} >--" gY 'ja+9ry8su0H _ݒ>DL|3Y}ǟyעt0ϟkg NqXnTuw5 *s\o=:Օl5 j-]%ٌZ0|=kʻ Mr^3tW7G62ր,yo]-^YVuBq6h}bϞ5i gR P8Y@<-.=½q1[N7?ԦU0>(vxe%OpU#wQ ]Es6ߦ!',cҮ5BVOۧX3𗓭+21=C̨cCa"} {{{ƭ֕xk$A*D "D% JA (Ajk]]|Um?Tv[W#k-Mf1]D݋K)[ھ?*y8p&+. yeIDe}{߸ E'|#yF^C>1hIENDB`ukui-biometric-auth/images/Other/08.png0000664000175000017500000000342215167732630016665 0ustar fengfengPNG  IHDRbbIDATx흻TG؁s[X p1cp` 66 %&S`YC ܶLOm˲3%~՗3TwH"r[Dol3Dl ;] oqC{a$"/`zRovQSc]_:vZJ=#, _w=jg$})_jAՑxUDDW1zD% JA (AQD "D8fhOD<\W\(A0*X<Z)=VB[`i>V<+5ٖ vaʌgXv]'X_ޯ} c3< Ϟ1g8Ջ>&R痢ߨ 0}@xeU(s%+ CfG7 = jۥ=bS{Fm af[{ˮ FXV>4m_ V1dY+x6f65Ho;* k64u aOU þ? _ĀعccJ)jl]2xsն7k1Ȁz`Z,{N;Z8vIaa'TkxOTc#(\KD.%:eXFny)yP/Z/v][{ ثx3IPJ+S۫2?(AQD "D% JA (AQD "D% JA (AQD "D% JA (AQD "D% JA.NZѝ^<[+Ī*pXnILFqTjw𢎸/d] 7iэ x:/++OІIoW#c,C4nLsj,;,b83Ny59Zϴp*t`[060*1VJmͅϱ {,\6lLl `#+te{9j !^t4n@mוֹV;OTУate?J+S8X0qY-zWf$ l!|ןѵ OF{O:6}[.QZ<[aCs  ^68XogOXOj=T ]~R?l7j!ޱ>Ҋ.i؅[YSߕ.=-@py[)x3 Mc52]7}6{Hkg]KN!ZhW.:_!^ڇw[},,}x O>+иo:o]7~rm0'uU뾳Vcf. Db;' JA4ߢ39ROd^'2#)AQD "D% JA A|qY>ؼym=T[j=/jM春6QD6xz)8;R_ԁS'n`bǢ[XX!< ]g7D v;i<ᆯHD^`g"r?|4g IENDB`ukui-biometric-auth/images/Other/09.png0000664000175000017500000000343615167732630016673 0ustar fengfengPNG  IHDRbbIDATx흽r7V$H3v'p+vN~ TǍ̤uZd&)*+`?Nx X,I ,5$@"LD~e]@%">| Zw#:))7 侳IDNɝϱ{=p6惟W~ID.<?ՁkxDDr74C"TpD‰' N (@8Qp;!IDrJ)F‰' =zKyWmj_*~^I7ԖBE7 "aiйƔD,djZj` 7ܜ;]8Bk(kPZU,Ba 1 ԧ&т86a6R?EuEDiJRl3ܔ"fWi3j@XV9 dAm6(Z|N덵-K^(hPqTcڔ5o@j6`pfT뇍T[JWmQwOj&)v Rbnn94TW~iޟ9m=ͩniu#s\u)J`B)Z`6[/)nOS0F "z |c:>F Gr0TŦ+.ֶ4=q^yMR Rh\u]ӱ]Kj\Ed`jx ~68a710rB:t}MM~  Dk:fjUn׹&sSC 4K}uD‰' N (@8QpD‰' N (@8QpD‰' N (@8QpDMZxGRr_*e ҹJ&l GmG7.>ُk6!k~ڼwm]y4Mȶm7!]6)Ś&cmB M Q=Ρh9 UKH(W=oǃ 尥i4Cz6C,x5ȐOO&' ) PK`)9u^ 9ڋ-^߿~~PYB1]zIENDB`ukui-biometric-auth/images/Other/10.png0000664000175000017500000000353615167732630016664 0ustar fengfengPNG  IHDRbb%IDATx]=E}09);$NmRq*AئЎY];m_j]h^VWқ: "D䉈[_\H!"kIDD.l Z;o:)_ <;y``I.h1EGCDO&Œ[ITck9_siNڥW{jNJd@D4}xgR陈j![+4m~ 3J4Bf %Iz<ؗK>DL#o in l+!wdO:6l~JEۋ[mѶ)k񑎕 u1]HE4LD>Ǟ#VÝ}Gsi t ~v,GA%"*APJDT" DA%"*APJDT" D*i%_Iz_K.՟'RNVIm< m ߷h f4oT ;(X8HOȽ'` =PV["WKņsz`CbJ&>g_ik`:[%^VF3]quGsubbwcY^{BNڨH =9Ȭ$r8XJ)G|\UqL.9*Xp=VNlΓ\r*I.aşjZW$^[K.'foNt+](Ju%BSu߫D]TЋvpN-poի*J[JU{;J{[b^W6!X<$^dώ!,ܲk'/mR)~-lBB~^^w3]JjkGp[bik`~vom`\cA\6xOǶn+pKS&>`'Jv]pI'i)냛6ﯽKU^!/'Rxx;riʱюPDx')\ضp]~  DA%"*APJDT"`,EӠ39R_dFB%"*APJDT" D`8^*qC}:0dIDaK)Ly7)<`bǂXXIx9X@Dds\xx -vVCy@Dlௗ" `ܯAIENDB`ukui-biometric-auth/images/Other/14.png0000664000175000017500000000121515167732630016660 0ustar fengfengPNG  IHDRbbTIDATx1nAoVAAN Bc: uLKkܤEimerGYA$QoS`jM@C k=El%0&DBH a"!L$׍ p];I2\_M6DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH}c&DBH a"!L$0&DBH a"!L$0&DBH a"!L$0&DBH.7M'L' a"!L$0&DBH!5b~yqQ?U\֛W/LegQWJׅ90 6lϸp^lIC iqsݴX6ېy]HoD+9|IENDB`ukui-biometric-auth/images/ukui-loginopt-voice.svg0000664000175000017500000000330415167732630021300 0ustar fengfengukui-biometric-auth/images/ukui-loginopt-fingervein.svg0000664000175000017500000000255515167732630022336 0ustar fengfengukui-biometric-auth/images/CMakeLists.txt0000664000175000017500000000054415167732630017411 0ustar fengfengfile(GLOB images LIST_DIRECTORIES false *.png *.gif *.svg) file(GLOB children *) set(dirlist "") foreach(child ${children}) if(IS_DIRECTORY ${child}) list(APPEND dirlist ${child}) endif() endforeach() install(FILES ${images} DESTINATION ${UKUI_BIOMETRIC_DIR}/images) install(DIRECTORY ${dirlist} DESTINATION ${UKUI_BIOMETRIC_DIR}/images) ukui-biometric-auth/images/ukui-loginopt-iris.svg0000664000175000017500000000177215167732630021150 0ustar fengfengukui-biometric-auth/images/ukui-loginopt-qrcode.svg0000664000175000017500000000203415167732630021447 0ustar fengfengukui-biometric-auth/images/ukui-loginopt-ukey.svg0000664000175000017500000000367115167732630021157 0ustar fengfeng ukui-biometric-auth/images/ukui-loginopt-face.svg0000664000175000017500000000210515167732630021067 0ustar fengfengukui-biometric-auth/images/VoicePrint.png0000664000175000017500000000252615167732630017443 0ustar fengfengPNG  IHDRg- pHYs  ~IDATxAN@MP"n(a}.`A Y4]|H\ >AD RqObB#ϧ3ۻ_ }G36[ 1A@@@_r-@ @@@@Tt()RM`RF%,J͊R#n/XࡤdoEyQjm C$8vC-f>I}#IWEiQmWY]}D<\ VT,U_N>]u8qѰBB0p %)9"sI02 `4 ?-% ƃ{BU1%\򊒱B̷bhDRR3R@*Eh9+]\xQ0"F@(x}h/nj/oht2h r /-``ˊnB@K|&@@@@:)B 4 M݄L G"n1l"%~K$tZE6ϖ;%Fn϶( Ig#V]Q}]IYٍztt޾]R6wO*0M\%A)X25(Aj#ДA6\nlsg1_B]wddF!!ݡΧ\vyX@[&em_# o M Uגr/D: E!˰GS%z_..B]`"$tB R~b*ЄP}1k~\e RU<撫]E Xt5sȍK!` *I_q@ 6gD@@@@@}{,CIW$ڍꂮAX~R#oRGrL}IOGA$إ`_6^B@яEU@nJY`Wj;}o_k|Li_w@&)>a$BHv%2}}~m5E!s-&HP7b]$Ur`:@@@@8c@Z**`@@@@@@@@@@@@@@@@@@/6Zm[Hd|"%yAIENDB`ukui-biometric-auth/images/FingerVein.png0000664000175000017500000004203415167732630017413 0ustar fengfengPNG  IHDRg- pHYs.#.#x?v8(iTXtXML:com.adobe.xmp Adobe Photoshop CC 2017 (Windows) 2018-06-22T10:02:14+08:00 2018-07-02T11:02:17+08:00 2018-07-02T11:02:17+08:00 image/png 3 xmp.iid:105d8a11-238c-4346-b82a-5ee9136f7d21 xmp.did:105d8a11-238c-4346-b82a-5ee9136f7d21 xmp.did:105d8a11-238c-4346-b82a-5ee9136f7d21 created xmp.iid:105d8a11-238c-4346-b82a-5ee9136f7d21 2018-06-22T10:02:14+08:00 Adobe Photoshop CC 2017 (Windows) 1 3000000/10000 3000000/10000 2 65535 160 160 Ro cHRMz%u0`:o_F nIDATx읿o #I'/ҤX[ cMA+m1M 4)k4V%@ᔩ6ik#&v+UaTNK/H")*,4{ϣPz8=u `y<3g|`$pE^ ^XX8K6 tcgq&s)IIWTgF `Xa_p5.xJB:o&.=|rp[ Tn~#ؼL 9Y}K S8+hR%r;)|aIoq `sxwMΫp&;@7\f\eB?SW)-F(yBؚڿ&鄗0g,;kM㤸ᗦWG>䨂NW=q-GR< oܝ uU3kF;UH.n|N[): t%g$Koԅw`.9`ZxRJ$X7ռؐ%T.N99>Q U/>P±D.e-,1S+6Y~O{<}p63B!V~&]_G˅5| `WA]TplLh!#װ.Tj 7Sdž4L.$l23-i܌H&ӛ.w8jESljO~}l/~A$u!gtňN cZ8T*$+~q* BsBmL^\7`xmxPP'ņn€!kw_>% ={ mԶ0y'1G)_x q1CmĕY&\gG147<%5¾V-Op7eI#Cf )=w26Z}1Ow< ¬nJfMO4-xR``qk-Qi^Ňrs ym[\)zUP|]cp¶94sf8_dڥs]C9 cz?`!(>$^i (sWD竤Hx1N8` 2+*Y ne_⃡S|0ڊ^XwK \NC/,~S{ H-/FE 0wWk?2F?2&;`ͯ-Թۏ5ϝ#\0tT?0wpmse)><ܶ0PrBa"Yȇr}$eK$ aOEN2,ʋ7`X&YF> `eGgX&9@dX&{.rayB8+EEC@xYJ6,'@2SR]鎥 NJyP JS4\TKrAUt,x0.}Zѣ)Ry$W37; W1M,ax;)7  A]pvL䂪"AslwL_ P P:gaBS^N17$JKDX&9O `DXZc AU_#yA$F?&Cf+YI `ek4A$eiߨHu lT${);k) ^DW٨U~N1- nӱ 0-r3eQA]4Ri N C?"̨q|.ɪpTBgPoy+S6r3/EѰ B4ʜ1"oG0a4/C~ B:,np%l1Qʃ=d옦`UWS1ðdz `-3R)HQ"E)HQtVjMIENDB`ukui-biometric-auth/images/Face/0000775000175000017500000000000015167732630015504 5ustar fengfengukui-biometric-auth/images/Face/16.png0000664000175000017500000000743615167732630016452 0ustar fengfengPNG  IHDRbbIDATx]MlIjfl;*ц awClâH"p !!bnH{`…4$^,-"Zד7q=C~S=]g?TS]z^hfh+񘂈[,ݰ mlDy͉ D4CDSzC "b.yɓ3c&`Jڸw Dt&{a&:] D4TDDR#\+b[7\ `JI/-tF0)Kڍ)"heQMk6bEnWRǸ_j0$l0Ma̓?ό6)ɿD0 kx!c$qӔ4vCˈATא"*a҃ӦhcD}K bu(7K&v]X;;JF'X0Bk DPnʥKaiC˞ȖeޅG I&=dp\`w5@us!ˇLXǧhSO৙@)&}-ND4m=wd1]Q% # _|Kc*l:Y?Bc"Z3dDa:]=kq9 8>F%QּgЉ] n#i܏%>j*Bau3E ]#ήn}u&a'D0hKQ"IӴy&",-׈ ANG׈\ r|WX#gQ>ug(=rn/&3MCO"U`7GCDT5mm% 9[C &}/8_P1hh w|aU"J-u"( -\r/mkt|nd`Ht?zM0i`!xФ1ADw@ ~h$c׈ "68=!&(ko9F ]˙ &%Q"A 9r Z?np 5 h[4܉8O0؁&W\v_NBE{Фx*JRA`r rL~ Zpc;5hOP "6yր|?||>]4 ^TR^kxX!@fHR r!M8 9Tf e2HG iYCb&#6) d ~;e~5h.oCwY͢E[|> F}wQgoe",-0D R6_8mZ=hYhO`fZ0\;g877D,=rՎ` aR!8dha;m97dsH/S~]odDDX$H"MVvGFwm4j|07k֎@GskD A &!h?Jkd:-A wD3"$ M!A|-[;칙:X"$jf"lAQis4[-9$CG%w+4f=7'#p24 ط 2=.׵A!FIA1  diܖ+,1Yڙ( 2&rnľؖ&,h|{ԉXZZgW }X.&!g2a=0i|=UJ=rV[!pܹ'RN~@X.-- >5gn O /fEvyOWZg/5 `0o̜Yf=o 8=E}=#iNAY/z/k*kuߏp'?)=h+\030ṿ/h[a¤Px\2DqIC~7W$t "+3 C$E8*aa[$FA50X3Z #JJHkz& pDP0gnD7 > n'o$42],H| ҮdGIPz ~zC9/<ܳg,Pn!:q&K'BKqHy鮫B eaYѷ̬?_]QuLtG7YjJT1#Y }o~'"z8< f^&13 EBQ&}Hx5#'jv Md3oCFGxT_"hT(p7 0l¿` ifFaF 5Ri033ɨ?$Gp;>.A\ +ci> [ |E (G_[8"]ӄÎF-5*xyOx7_n7[UQ.4e?rb q] ֮{^a"͜ \!s;SAXp.DNTVw%GXa&Ci tIQh-M*o[ڽfPNW"Oxnߧp^/ /̜'ZD^Xa](}B'}S}Euzsp?Bwwwcmm5t`}}}6H"aPOZ^KX]]nZRJ X5Lu Dtmf~&RCĈvW쬮nO*(b63OJKIEa"D[B@.{64G!lRR%`ZemuXLk\,//"v>O#S"dJl"2qBD4TV+!JƇJ%W(~TM J%w)HuO>q~~|# N$X[[kZ>Ѷ~w%ёGAv3lL3IQ.{"jz.,qܹ41 e3v%Z^RDuIbhy5FDRuB4Lc0߈ ƈmHp,s-#D¯j;7o޼!mFPz%!ī`Dr*vL#v"\*Q$ xGMU Ee=}BV{%¼ɴb'/Hn\B̸[!v"Tt'p:ZRZd06|=0T_uޱck֧GC{R@="BѸ6FDMjvb4&;Jv5Dض}:h4Yu^.f6#06"gy|蚖l~mRjm׶׷o~tΝNjsXpR Z<8ӆrSp";X(9Rzyz^7wgc@m0S`8#"%oTأFBZeɲ4I)=8귧w-en_k<2Q쪎؈X]]&}"ZXXH8&tN<$}!LTgIRyz޶3:c----0mۯF+p]7KDW|oLLjUY)<3O3sP(<3e'ԡ)QϘʊ11^qyS׵ZyT!XnݺtvrKf[A"ƅ7o|ށ/>hR9I^_}¯뵴 u ^oĭ&k r*>"t:;IL]/\qK@D?fRy5-B 'O6l*'NDZj:֮l6YkEǹ9cYu,&"t4fyIxEJi|06aDJm/,'9cK @ ֬P(,8i>JBLfD:'ED^^U/QFڌ#xbƲq+ٔz%z. 5"d@RIڞ'. ۶sS \mMwH m6]ap"5Df )(8c߻H SSSl6Yn\*P{Iy{@(#uS5zJq,o@&ya2e~lC 3?H*RM1r%Gc'jzhӧ>}5Ԕ^똸ࣱꖂLRnv*Dz>HHBW,;\n+\&Z#ƅVuC2X~>Q$h4<ϻ_ѾyiX+v] h_JlJe*`UЎXRWϘdGMLDT*eY333n;+ׂljT8uBݞzfBV69;XзG=my{ICnBp9hbcZmEu﷈h߶ӓ$zerG绯's\C$8ǮwC\#g|A _xܿ\~7 %`9yx #xh2Hl=#iz\|=,ϘDfO ;fLTԧSmIENDB`ukui-biometric-auth/images/Face/07.png0000664000175000017500000000731215167732630016443 0ustar fengfengPNG  IHDRbbIDATx]Uzfz>llqvzfplX) ! (Y$@""!!$(a/I&qmav+ql<ýwNmxjJ~={V8ayQDNm8# 9 9Y("&2Lv_-d2OȧD乜x`Ϣ{Z0ND} cUbKCl? 4AU"KF <$eRR HBGg$<$g6OWi ZSiDķOh>.0|8)4)1tIO/#h*ZHd,&ȒC]B:@KBh/ ښj%&&6mh66khC=ܛ@97mt&c c]䛪$5_t&!F{+?Dgq NSwKHMȆMKuG1m4zmDAgdU=@~s ['gu#cdžH )?|?g~4 i'sIMqѽ:qg׉B6]C1z'rWD!"1 I{/az2tlٛJk5yZt/h zm5s%SP~fD8k>\a%lt֚o'Mq{k^#}hH`{~}~&Ck|= |~`Il8 ܈F6;97|J{=%:51I2\p dg} <z>2caĬ{<ځu@'ϗLa[hǤ'1#Cw{axfs%#p&p!Ao_6y| =GkJz=}fVs `ED'PR2Dt*ۇ6 }h[vI1BiKT:Fhxkq:뤩 qOdZB[ם:/;BKf4,;L,IkdZrRhdMLr5EG 8ݮ>3؁9E;$o{,NhTꡎԈ8~-ԒRwtt4P@^V yesJkהRK MLLtz]Z[iˌaG n?6jڣE᛬ړ[j'7FFF ?IprPD仓o2{: Ctttu% YT,Z($ C駟J_]]+ߵ꬐ ﳳ;o߾gͭ w.{3pA>󢉉 .WGQtVUjuj7&''ot]5U*Eq{YzDsy]&q7F;F8RKkQºq"Ҹtҕ|x{-..=^<Պ#Gv0 }xwFD.DLOOxHSO=u>|xǁyQRepN"?fm, >*_mg^6 Cߺq׋B;^ jYzIERZ<,r'bzzU*WE]/i~~J쭠P8yC_N;f+EsA4"]N($vyN@ 9iZ.(z; T/PJ-eb5VQ" 5C(R_U*yp A]3q=\^_0/{ʝ0 (J,s,^6 <џ;R"JVպl6 A`… (ڣZ|rWf/_~. *IJK݌T9qwʿcD~V$_-@kp ;P<SK,ͳ7? k;>R)TׯYqZ Rj)^T9333偁ݾ`o- ?117DQ*꽽sΝ[Hԉ)?444l6i̭Jr#e+CcFڕ|(垞D*D;zm&`E<J3 FT*I;FQZ `.Yp޾rs[˟Ȝ)0 4V_KD[|9"*=8a3ˡ=mtVa0|$47W+h2$D 4HD(icKȟ'DK "wXOB'">Λu"_Ndku&%J6n'ha#-< xNK_n |'4L\pv'Ax{6ms-ZX2JIMh6ǑI` Kkni7L{.5p8PJ}z?֍=lNUC`IE- 9 ګz-E`m͛\Ͱh|Ϙ{ei&a-OhXMl0鈖a i ۲߱Ԧn:@o~*$cڻ5Z^iNކϣ{?v~ = !l?C,Yk&_ۮvh0$%†Ny(҆A`6#w iwNtSGmg6m$Dk~d1c_@!GkߠGvShsdDUm֌o~] Ԁc8`Г2Nʎ o'uǠmn X~m9g[":6³8FN4/˴2nzԖD8@%}cӈpn"@GN.5I64hjA?4$kI=GYI: ֝u?̈́;iZ@=+aK&{h0a{J[>8vm[YYmGP(|O'rCg 'Г(́;瞻$nOh knduu |۴9,4;N~^J8Jl6? ;kI-Tա(zUC/mNW QX[[{I(˷<ϋ8FGGG,+q"D0@P'w155՜y^y@R)UVDx7pܹen,//Iĉ8wrZyw"rF( n }ԩ˧OTy@\rx"Dar|3<󆩩]WJuPH"@4'f 4't;>9A"Dܻw ~*^@"DǢ"җٶLSu]{p̙ښ$#buu>`z\^PJ%ԑgϞZRJ*J4֜ Ԓyǒ;KLOOEdlIcc{_0O<9*"}A;JңI7i'oT*8GzVK###zOR'\tiX,|<99Mjo [0- ].om)$ C;~mmmX,~lgi!WjCw}[ccc]NpcJ#EW]~W;AR)5"nסkMyYfp=,H.qTs0 q(}Yե뫯y fqk׮gi*ND^ĉ"y^Xzy'O6axw+j2!=&"}>_6 CߺqB;^Jj:F9y^T(nQn9SSSjZO(:zIv?7/+rʨy$fW9Ј _e\a$ K/rEDEHJe@)՛tI 7DzRj)%4_n[䆈Hgϐ=EQ{W!w`qqNZe8'r .D=Cq\ _eTTr=eND~E ‡i5;;;gqatbbRWDR)155l6wF./}9J\zXEO*fff2۝n Mk]kxx9?twt(usR8<>FaWaKB pkbEj:FjDV;|.E_1DK7 Ui₉hײ˞Dd1O/eZ=yɑs8Lǿ/&Gf3FPw6 v y."|[/vkIENDB`ukui-biometric-auth/images/Face/12.png0000664000175000017500000000766115167732630016446 0ustar fengfengPNG  IHDRbbxIDATxMlGv=Cz$RcGbdDD ;q$r([`m%|$!HK "XBY0$$3^y#:ZBC"/z.6g8=?P_ի=ADNђyJ!"Г9ݬ«mTRo " te׼3"\޾Oo,S%Z?Dƶ=7`ODdBu`DD1&oF8$ aH-]kI .hp;;Hʶ"BDo]ov}T?--`pu NǍ%lyB%5JMmZF/ud,yqs? Qٓ4 M\8HkLHkl!OoRܵλ".w*"3λ<=wADH]Z˞fI> 'vkl]]T-hIp;ArrQпߘDj,xDI)%rE%}FKZT+JG5%/"B .orST̮Sy>J.oMO>GF+L5o!Ir#ߟ]h J#]DaeJI摖BzH2>\]}Kڏg IJ ̨ -CiI}޾ g*m"s;,艃n69e5Ӯ\!C{ݪX-mݼ t+`)EZ:nY[|1YL)]Xk[{I]oOZBllNWR.ŝN~OOEy I^5<̛tyoRrׁ&'kdO.zGܾbVת5L_;3#<%7KY\ 7 lgLqMh[Gh[ ^7NӤ>~F9zΈ1*B3u."+.HZfpͫ*!igs 92ol+BL7%b,Qâ~%2jjG+BRcEDUqHņM-̺Fh?e,i|h5Y+ADa6  ,-G!Q_ teVA߄_!KjDr uY rhB 4)Ȁ<#"%-* 5ZGADBٞ\S@:kDttB&|Y7'C"2ۗDds[Dl[?GPR*=+UZ, n?5tDLjo c |[D.`F"r O2U"`'!<},紼iqJo"2ԍ1ЙeU|=R@ǒ~b%:7!V1VFP_^*OU $'ſaзP_z;P? |%l+"o0CɃEOu7a` ؂9E"\c&V=9􉞷25"-CwD_1qY2Sɥ6C@D>)u C$n-?> uu=nnwR#HSf+к8$"e].DBBl/?LBNxL2A<+ь:3}*[$dDmzPҚ!"ruWHBuH,)_/`' >bs/^;CáԱ /"1`u=t xF9e?7C|2;^.,0mg=Ip'ƺj;iG~/'#d KH4&³ylظNdNck,IE0 vVhDB Xה[*vup! yP("Y-"->ElH*6nwOmaЌ zקIǁQy'i7Id IP%ؑ N>){bO F+>'؉MQ$q9i }~AcDoiGS( d%ЊLDx$.&m~YO?x8w]xYkùIՌj) ۳7];n}-=†4ܜ )Z ̾HGEn/ w+ l &٭XE5+v7㻚@ 6vlhTqX !$0E>;=$$8Bܛ#/bgiE=4 7k֔%%%O>:}q |vH, AEK>moy`XP;M-*ó*GݖL%F2P;MX̍p6tX+kZc,wH(Aal k9gT1!(IuTMuW3KATM8oHHxDBnlv_677_~hmmmԩS1 hѫ0= żd{Mbr99\=BFB)@'Jl\..T/$@>/WՓhǏ b7/r'bzz^V8DQB7o?JZYYhlllm}[n `8 ;cccۥW §ϟuw[Dh@'w%>JDj[[[Ý+" B J`lun"*ʀKu~?QTA7DՆlDQt[m}C G=Vb?+Je(8kLjU +J_EOQ.(Fl޽{ADƘl]RƘAӓ4zV_`w9!n߾bEcܹӓ;w>3Ƭcj˹}a/s?Je@Dq\;1\.j#!fTZdV~qݣ#.Q)Ri@]ku-|nmwjA0mj~xV\T8mƘ8k?^wr_*:sssÇD..sQ>&"b688v177W ְ\ӛy0???VB\_y啡Cz (j"c[GDKi Zm~T*CQ `8}p 7FQnY+ ݞ(z_ u:-sssCO#RE"JOдBo܇ 7$!IENDB`ukui-biometric-auth/images/Face/04.png0000664000175000017500000000655515167732630016450 0ustar fengfengPNG  IHDRbb 4IDATx]Mo~fvE"ekC\V+E"+5j^R^^ /Ha6)z(ړąpJ  1ZkY+"ܷ vvwޙwgv$,_x7|Umq"hR`ґI& $]#MƘs2S~;~ c؎q\"z{Bc~DD -ah _\w"h'v:;9cD1~ x#ݼی 1HZ%h H[3upIKc|x.iwm~5n.e}8hFRBB蝎2".^Hz"A:6pvRކVYI "\AI9 !'ҹ &"@1WVHLn16Mh#@d+q\/QX9sƘݧV<͈1mP5\ JN%&GA|!=k|J3~Rd]i.BLIQQ &xGQ7hDԀKHі}kO  r< 'pw{-|؃BN$~uFԥnq,~HH%lAp  |Ux9Fjkf,d<(8~ H8% lh'gM`_Z˯R\&~'2 r'!u qќ*wxhDOU*ضvt]ٮϖܺuk+bX;<" ЄCX,>#͸!7;16""l DZ3n " Xi_LX`&` "&/_6@4+^eBx,JDcD u krn=}vh5LFDVا_U,*0BwuFs!c,9??*|N,frsL @|bc h,nyi شmۗ}>JvpgƈdT3LORAʊ2ahsb ϊ㸹B ^[z}/J=Um PH@\xepw---}:~ vF\92JҴm8vT*E+L4 /WVVi&yA.2̼;A(HLwJs 04UY}Vaجѣ(ʡXXX"1ι]TQ۫HGZ8?l2 4M qT 4"ya濰08}CŰ1C D44MS0041TuNJ @ Y",Jiȣ$ι=22"A9|Y*⩗mToy?['5M &+qs1ЈA%byN] VD躞Լ4*0ƒabCTOW6م&"6Dj =pmv dr *mI;b.D5CX*peLӌ)r" l۾###OT浳'lrp"}9rXfF,p?{7Blllض}1v9Wbi*V ,Wt0 cfѣvyFJYABl6[ORۀd,JQ/dFjzC|L)/]?^]]jV(e]/cemYiq CqΎ7 +'P(iSba|7nnh0\.wŶk{DTރ&&t" BJӴLk^eX+0 ۙZ6l6'x9mD"aQ($B!B^~t_ge ifl۞>V04X,kv1vY^l^Y^^~p4IR~Q0 -U'&(zMsy'"}mq;p?qp!dD4+uOoGZmI{7.:OO#Q'~~D$HŐ#"zSN6 IENDB`ukui-biometric-auth/images/Face/02.png0000664000175000017500000000572415167732630016443 0ustar fengfengPNG  IHDRbb IDATx]Mo~fHIW: ;8@n}z졇BO{/={ ) !@Xem$bqL"Ad_3$xgyg?d_d|}g™@M\`I1'x/n8($8+1#+}FZ \ gS=$ *NJ*tIGd_(/c,}sc/qfVq# Gr: I$CB GpܛtvOG!+k7؟}U!cJ@DGpuOCPI"Zq O؛v{1חg7啂r\N ORI ~\m8FH'B$(F冊׃_> <0i_2"-, )}79? S;FaWqZDkl3TrOVVIE [%!Ç~x͈HAFp bQ7B9>n*d0ÇdD$v/p?̹G\#s/1,l͕,h4ʝzBp<{iWՑܞ`706lllNMM剨9/G7 3wO˲93wo{l^{"$JO c,9wAիm6D4z~iaYDDh8RI=88J ߮mAؘD?3f9 +W,2LmcLm\[[#Bsee%5dFx<hmmm/tðDTjג̋D,Dض]|>"4C&!ĵFO:?6}`nZUJ!#0bm1kU)e3bkk9wcf9n!RڻF#_**sV5uwZ4+Wq--..ՑmDX,`0N,X__VX4WD#c0n|fdN3 >,155U^Z"a@DںZh6ׄ&c0 ꄳBjUUF# ttccccuBpL|iaYQ,0 c--Dȑ4mZ;o߾%0hZz%͈`_w9"'¶+ek`kҭug V5BKKK:ӊ"IQ׽-ι9/۶]:_gCDEX__O"뀶E!:Y_Tȶ$ڳ⒈@ǀ&Qǝ:40ЕFDErǀp8IDN1㏆Y4/Ngs> U r1~CDp]5U*4wu##B횦{'ۊ*4jԩ˲ kZ/3mT3f?"jE>Bq_NLQ⒈ "޾}aG9-JDβEiB80so/*߿_ޗ5JDFp8skp:0"WuDFc1[ZZJ8P :tNfr˵Zm>ʸD"xeȍMOLܭT*;+m;s]`U-VmgDT aTz3JMSžя7{-2;j^MbYqΝ{h?l HDә~'XU*t}9%aqv{usnR+l.y Dbuu5v+XuMAZvQ{Dh? PuBkI5,2ϟo'صi-3v"R+gv^t{|Z+Ͳ,09`bDPmӈp[q<'0d6@24tUÐTiZ횦 оseY !`Zm/JRnK✻Lf[G:gEDun䬗7t4j/`+mA<}ts^6 c3j%TQF$lC*s\VsTafгkm}P IRC?gڲMUaH n Y3$!m\׍|y"r,z=mm)?[ "!!S8Nle$NeY뺷 ɼҙξ4?alrp"zDD@VgHJzy8DHsL}D&뺟0777cnnn kȁس8u?mghEa&H-`&IB j:Dn^kt:~TE'}ҟ~ATtǹ8vm. !nJEء ; k'ha765eYFV3_'?y51h4ari<U<ʸjzp˲a󼙠/u]feu}s4w&}y`vuy9X(>ՈV*_uCdTt^ܽ{y8O%˲(V?tADRcO&/hH?-(/D"y w.9"/?Ύ3F@WGE)}}\Ԁ?&OxofIENDB`ukui-biometric-auth/images/Face/01.png0000664000175000017500000000501415167732630016432 0ustar fengfengPNG  IHDRbb IDATxNOUmDDȅ+;Sx7#MafeɋHhL@vuiqK U]E'ש:UqG???+ IO!|9ƀPn/2D|O5NHy><ӜThwcy] ei㪺v@?DDBѝ([wBy^n7ǩ{Xd$mS.R+#jD\K#bR6"1"(ʏ%8VX\EBȏ70$DaB8/%߿[CiV!"lBRR6w9omZ!GQkooodqY 8Q@x< 1(d1 ݻi_{4ͥt:$1D8#mZ+Djǃ`snDZ!z']ocV;Fďs{cc1bb2<ǝZvWQVqJrOgZy^N #8⼈D"q 9h4ҺC`:*# l>2eRU*pιf56QСB)L.t:CnR!bjV|_W>dm4\.WJR߬4|s~-]E:l60 l6m۟+!wCUPn}L&d2 DbfQ\Lgߧ?̃177z qe- aR!Z=ιM`N,(ʚWeB44!!*4%S3x dضٔì8ce˲ε!fҔR溮QsYX[[{9q:Jv%Ji+b QBxv%8T@ [8^׾A!qB2.B "=YzxrrK)eҼyrHB4Kye{{{ (aEVuEu[:Y_WD_3r+! aB­p+! a*&t t=Bvغh .$ 6 F$ !lLBŶ!D^.5čxQَ@iB4ͥ^oD0~[ST:mH9\bm׶7O<ٕ I9\X 'aF^9$;|)B4eJ)}5Vx ðj^Nښ b"j=p?B{{{ՔZ!YQ aJ(KX^_iY ǹ9cY phS!iY[[{gbqsn`vFu\.wm `YDZPs"k"˕|_VOtD)eDb_E|ՏHg⿊_xGznꬼ@"K-"~DyFħp CI$uĐIENDB`ukui-biometric-auth/images/Face/13.png0000664000175000017500000001002615167732630016434 0ustar fengfengPNG  IHDRbbIDATx_lI^?3c{UV$w'dža=-,'!B H#BJxY!@B ݃XqQ8l]x8g'~RtWWUկ~]3DdLD΋Ȝs Ԇ\ϋX gۨ0=~An.xD䬈ٞYi' E9pڷqϭ "ryK̻cDdRebDD1&=p/ݑ$ĺu))+ցE5ƬuB_h: '5MuU~$eKy!"34x7]>ꧼ/SƘ{kpO=n|$UaZ6ޞ['S%^$\f/f]G~"#O"F 1;`2"oȅJgǰс=-P7Cb7ˉjgdAĜvq﬈e(w:K9-m]{) mh3RrkL"q?'bE>AkFi؊9idp+&Edyu}(6&VGڗi%GZ+i>x~8swzK e-]i}޹Iw6]Lέ9l=u&ײ,@{t0d]sHr[\ԏgRĆ[aNe1aGx+K_wALM^ȌMxJz͜zg6?$^I7 eif-}Ӓ!Os4V=G-x[iotfQطtb]mEv6OSooZBlΈUP.ƍ%'l'N#ļB⭆՛&]@7r7.k5GHPp={#KPnW{{U>yz,.y&j"Jݘ&gr^}絭ݫiR3QmKɊoi=GˌcT'iFԙ8Il"iǚy`3o1Ϻ16=駚%׀%aX !1Ƽ>jm!-\RcWEDv;UpHǺM5ʺi?di s  5WE$jƘ=kJ"],%16%LR뤓Fk`hFB8}O5b2Bc(yI.ƞPJZ>]ӿO<$ I2Q=9 zP^ @Հ^4dWDY]3,iGBld#/9O8 wl'/_jX}.BVD$1 |`Z)xE7/-4"Kr"KX/nX>s : "OjG[D( ĂwD4<K׀S_W &p ;WeGK*fd1CP_SUkfBo5yI# N 5P U2Z~ |2MV|K?=b1{ +4GKjo`Gyu~o=Ě?jEVʣ_>'+;yOk [I#<|$!9oaMohu_|_ywF:^ X®cɸGlKX7f~XN4vHܠ{jI71;F}$!z;o| 8]>ܫX=šAbb&X%#;^'jk'=K&D$GF"0:Mz7~fVCn&ɥ!pVN}?"vs_Ժ~aMCư!Y?Ć}L.ЎIPQz' _PKs?+؅c+ƽɾ#֍a͏$ M_~=d;,=(%wiSD}X7JDr$ ~xyǎ!G#j;vD$I]N&_i'DF>'MN> ?F6s󕫫if ܶ oWj"R/)JQJNK >)L~) _EcL888OX3rE)Ǿ)ݪuu;(˅Ǐhyx333] 1~XfeL}ccf 9rd=zPE ¥۽lrJ2R׏G]JmfA'&&O ¡nW. "*@E~!KKK (*_^^>ԍvrرc9T*Vn;333(a.˅VG O:^kA ;Y0 D@{u|M!"UZ6ڪl+"[o+&1fU<7DT*FʽRT6 w y p-<ӭ6JR@D J2hEnj>@J܉(˅0 J'lkmmm=sm@O-8q ƘAN/⒘;Z/p_C:G']0 _65y\*W\ib:NPPj~pM^hrpԩǏNK 0ȝNm!Bu&;P,RVvJe$ A&&c4&0 71zgy0 _xׯN'=mPޮ_(˅N:ْ!z!WEtʯK-4I2||1(-3tocw⯎?C6{6Y ?DA ?>4 RAPf|WIENDB`ukui-biometric-auth/images/Face/17.png0000664000175000017500000000723115167732630016444 0ustar fengfengPNG  IHDRbb`IDATx]oGNNPA uZ$|@<@y@OF H UB !ٕ*]ɖ@@}`I;ߏٽ=ߝݟݽ77|;($@rU6_,ᄂR 9Y.+@G;]ȭ~\%9OrOvlArVd佨s]O YmNH4elL+v@rFd$Ab'V~W[7b x7 $\sUDR$'p-޶fe(R  V|B9 =1n8igМ!aCn"qd$b#@Dc:&`l52BD7Rvv8d6&h`{GMr>v~j VHz'yw>ܽÑhCjHLZbK^0BOnlfE`;2>nʿ>Ōs~:!Za2焘HoB-s d*2rc+*a9M'Ez2OrCϒ;8z(+y=^kL'R,餸R9!qQb'ܡaAȹ]&q/T`͕e{A\HQoL?є $}kNU"`YT ^cSGi_i rA"Ifm"=`X8 rd)YdA=ly84X(ACfY# T1D?u, " Aր_`8iګ{5I=(_hzu#!BB9WH&19n,p!*OehfW\p}o&*5IoG4X`n2żU$oSu.C}$7ͨr: 2a`4-'<̢v _YU֩MFo"l::Q2Ư\kJpBz!*'BHWM 24A!{$oJ]^+d c1pjV4/'|L2K*}Џ]~#Mi֗U>i*<Jra 2b`>ȋag؎ruIXFE""d"\$="OӴ&i2ftXXn0€is2bv3eEo ј٘Mk:H4~+c~rB)Qy&3!jQf{$=<~Y$)%!s}(hRMfY+ӥ=CSM"XUOd hrPӯ}U;vLul3I.6p'-k:D/fOX%yK$K(S$O6A$!#1 \TZؓIY* y;_ M_)?b৲?` oZ;m9\s 6 hhpfaރ$-CW%ܗ'ge? >0d1  n X{dFv+^W1%c7 `'$ϫ0ZuIhډO#I 13"x$ Lr&%W"HԦ%t&5Sy`\tQR{>Fg !0Ԃ 8"/ZlEN"?pV":m&8&|$QS N+"b}BUj4o aDjM6#/tQ$iNkR}؍d"B'%EkE" dX h ԂF]aF5%R:BGR!JMQUAEJ,@GKJ=>E_ݖ_ X!䑯v"BHE(lKĹ&kG5‡ 8ޓxgK(\t'o$FFFܹs_:o맋sjsAذ}[[[ ybyyxʕ㇇I B^?'ywzzQ̅F[aRW^]uz|P8>g׮]{4bkkkhlk ATڛr z xtSfJr19rq}}t4|=NmdK&I^ehFV"#I"n#֘Ip041j2!b7qڅtفM*i.}o|HTG/q8MDw>J>;;>46I9og!?Qa1K1O srk,Y&(|к!6RB&7+ %Yx=Aeb* g'8] d/d\f["j(ȟa:?UN aE6,q㸇n]^"F40^sj9 \-?I'p2$^6H bROs|nH!\3mJoޗgF1΍p8b5ny4詃an\2UQuAQ d\Ƈ/Trjjz)Ԃ9Ty$6tEik݈$B[ 9D{7$[Ls\ ɃtZD;>RɬEo"L uF1B\ Uz#ƽ0zKW+jNڛ kkuMEԸ6{~ ~4B;/5hewۥE_.A@7쭉(rueme@j4})| GBbvW l͘2y71Mp]]FyYޛf )OߥDE×U_yz,Ӂ!6QqԦeNeqn;۳(xvDFWl yoM@%(QƜ[6Ԅ$\F I_!"#0 njD3: }ʢ!h$@ Nm(_&:=m!v26OՍՐjp"P,c_k~D|5"qyYHPR ^c646u&@ @ R_3Y@=~V2}Yp9-5C{b'P=v2,(AkihR& %㞬qLNEs P°i~O&0Ul׈JD}v\#*@'*<ɛP03P"ξ [P:{~;ԃk-DFBMI>քD ۜMn ).M!Į5!D0).PD| =(f02L}B j =px >eN'bӔA[|슈)(ǗA 3|_@Q'L2Q 2R' /8o][ &ס|*ڍE64|"^Z'O'P;7|2AO@9 }Kpg)(?sڳ~%<_!96M(B"G[5O@M^E/rA9N4Q`,ʵA=,|=|e E)q>uh;( 1a߈5i$P$e(yL"t~V4]#s eB%,B (w%(hk@ W>Q(P"ڈ;" A Wl7c͖&t2EP +9m7M?sfTdSmv\i@in£6Spfrq>5z+By |+Q\*,ץ4m+ 4uq44gCTU" Ǭa_I/A0巳0׌>C @oY#5If'm3M0KWW`xQqE#t́͢6IY"b'&0֘ A(@9JDCb-p8-)Q> SVX(X3-}PN[;JTXzYW M A28!>nP F01H{@vJ)6 <btD; %cC w?0?rJ+)W4)HIA9a#찑aZsg[UZ Iס&jcϯ s+h~`Ck9碏#'\NS&8 5ͱrbܘ P_ BfᇧA36)\_A6YNXqeixwݻwgb>n|gT:!t6Y~CY9!Ī2;<<|e' @Tzh59c Qm[?"ϧG\=q>O,єӞQwvv򫩯_ޝdz+]#GFFޏ,qOJ5۶0˽jqɓۖoll,f2?6"4fff5Fm k1!a);<<̺`FDI4xwq=qqkB{%Ֆ}may6߾}nDV8q:JI/ӊf8eYR>8wZ{F"DJ)]"8~xo3?ql)qA45| "BJHD#4m۾eY8U=+ @DsP(~W0$)J⨧^$NXP(<+Gpft7 Qĭ[Y˲4zMO<*-I-IǏ>""lnnfM-Emc@!Bk9;c7h"㪃uݎ-CD[[[7o)q"DZ\T*u?κ.!㬫VHsjyxxb_)166V*J`ss%P9/&шcB޹s);w| XB5U#.q% |>MDIOyh7G8c MBpCCCLfPB' MՈ^=t7הK~wٳgc +aK bffX,/bqN>v!Īy'O/ƽ v"2,<PNJզDZ{4xSTmƍˍ&DLMMe,fYsrQ.{8u̙Rt@ku]w-N!hJm~X,mw|>)e60 ӈ\.7kBU۶%SWN:uc7ej-SSSC$8ՈU'['vԿ'䚴gqI ;/'Ӗ= -[/T8h 9G ~pǿb{<2ՏӑD@)4М1 (;*>?VdE7IENDB`ukui-biometric-auth/images/Face/15.png0000664000175000017500000000776715167732630016460 0ustar fengfengPNG  IHDRbbIDATxh\u?͌doY R+q4P?jܔB[ MK?_ r+E؅B)BZ^1PB&|nAD޳qnؓW/cvÞD8ݐ8ĺu [V0Ƭ}y'4BMpIٓaexכ]:B^Ic-qS+5$myGF#LC;ϮBibn_Iq;mRxűTDeܴ[v :tҭkY&_s =9$ AWW,gFžSh+4xdm teikȍ"^Iy!3J6BgloӜ{gFm>$I2$)J'uh҈W4FL{aU?}K,FXyFkC,RP.ƍlCn`[A!Raf~,Mj;uDu&Jn³>Zݫ0MlrGxBN Yxj"JޭVL39ZװWek٫iRs&w)Y%4"hQc̪ lle LDV%2δc42K^^M/hhnLV6]FO[}i7Z3JUma2EL]Dnv7y6e]I8Ikշm!B/hW^DsvyMֹƱBD<d׈IMόvqMW2Mmu KkPGۈ0|8p k7ɲY;Ĥۋ4Bs/OyLLd2U=Itx&囖׾[>,géDdoktK,_^EЈȗE䚈<#"}"rDDt;Zg;/"/=}"rNDwxۤ6pphBA3zmFHQD>'"#"+J{AyVپj*"&"?/"ϋȠu"}ܼ3 M|Vwέ|]`(`ۺ%?JJj}o.=چ?{ց!Pv1VI?'"p p4^45 Xx|+lk^'"g_ƒ&~~ 1\USmXjFHeuW_B0 OƫE >6D<kP~ _}| KP @("m&DH(aҢ EC8}#'c85+dwI'C).ZWH'a;1fuYŐ#q2)yl>P%" 4pHH_Եxi%QVh%H؎L^o? Vq2 2_Id(=vD8JXšD2<|e;2#|)J/a=o`]cOc'tj[Xs<$2|<sK׀ ;_ND@형&D꒑iB''!鸑֔pD[ 9Mi IZVK>ծmnh ؉?J{K~ZfFx3I:nDP\k;>,V[Xm(b'gN`{z.kro7ƄP =ߙ@㽼^/_>M&f$ ҍW,$a;7p$(~I;/V79 {T*A0umV*nP.GEk[Z<|pkuuu… ^*S0pرBDZ-uAM™3g>5.J7o>h71m'baaaP(2{mJܹN= -;wnp{{q%AanUDvmm!\.UՏP,߭T*:mwۉr< 6sθ|02l^nևa /x e:o[u'b?wz~{Mzb1|@-r!'?^'Gi8,OH8\16O%/h3܃׮O'ʼnG]IENDB`ukui-biometric-auth/images/Face/18.png0000664000175000017500000000671115167732630016447 0ustar fengfengPNG  IHDRbb IDATxo$Gn6"" (BEB\0xx/ l.BHH .7فF|zi$I ~1H .7X$5޴tpl~v@}>{IB=q3TSzi[A6=b پ$ɏQW:T8\FIKDn TEۅqȺ ,[q(MAĤK#Iֈ(w=&G= (:$4=FADG=.g!+hLiYD0|:P~Tw&pEE$귍 硣fI.y1m"")Y+6hW>[2u: 9K+XUЂ~/ ~r@^&Z˗D`&m6k6 1XV҇Իy?LXt6nC &($IrMD.k]JP d c+1cNuMӊ_i,9+Oh(8t]F۸iݗ]=l*NѪǰ&bb1Kαm}#)v&azꇊ#mzvO"F9ih75D x*kDS&W4rM;ek>PЈH+P& v~3YDS9ٓ4CcSfCF8L,E}$Kcd?zRt.3r-?uL9I uSZؑU+.]RkI]]Mӡ !$`b]['LxxjDIWHDreϹ2ܩhύHj:<`$@j$g"ѓUg YP>g^ ]װ$ I[!'$H -qRR!2"%LZG4@+Ze/R}Y2EsOBT"Њ2,#XgmLN RamD|.省Usa0 cAMT+a_U'T:MU~6ƴ|d D_,h{JU>Vak!iŚOUd {!ZΧ<,N os;ZfXaQ\7+{:Q-!:i^FIK¸TPnUCN4-K: eb>FGŞ$EN-gV "woH$ɱUCG N3V}/) >O>_<CSP[Ib 8VV~'Yh I<9!% ?# %"~~3r"D ڧYxkDa' [r3% m%GH4f$D%zQn}i~~۶<"qD%A{ϐI*"2 &exx;G+##Cw#aH9$9)PᛴYCAUyРVE(  fxR CMjȀ,![HL{p+B4Z{L ԪQLDH Ocq˷> % yAf@r;O6'jo&lgRՓU"-D##œ1#kd=22["Y 88p'=໤ [xLD@|)dGOwHOw1ddJ9 >#!=9-fٶdd~/"KB޾~x?3ׁը ="22%onÅ_ g;[ EerT41۾\>JXyB)k ]<l f9" .r~2ٷV!pM끷C\/pt Y78 E$^OQ';xn[<~ MT#Y Q!ar}x '?Z%0OBByfji 5!$ӽח(CR8G%FZUKq ּxN{6q.xP &%+;ش gr0Lno[\a(#Qy& %Y&!j:pqG”CNߦM;3k?sC]+ RqmԇdN-sp=bmԄ/n֤>k* K_Д, -?8X?2IENDB`ukui-biometric-auth/images/Face/05.png0000664000175000017500000000665315167732630016450 0ustar fengfengPNG  IHDRbb rIDATx_lI^?33p^KHpgc{r+Bwo <7#H]@X@9nBBVK.A)D琓Ed_ן#8sv=ևȻ"r-g{e!""~d}Cw3kk{m|V안|.)2S@Y\c}0MR7;JD@)߃U-`pz/2`DVZ&m]8TJ{JFހ Ut((p6 g,X- /W$E\A{A౗_fp%*<{4)}IMJ= "R7e`^ߤ[5#LڴKQRt1B7@$XqHIZ&Kqo4 X̘`qB`/&mo 8 --TpKɰc_SlQS&o~`Sz`~݋ч^<8Zt,2V/;WQt ?&?B8 z{P?qR B=ǎg_FUo[ $dId>Z5I{žotW8uh5 E:¶6)_W#t%ȘJC zOM;TG[Q@?E7x 7q!vEk@ WDv;"a"LGH .ZndG 'x^$5tYu=<:U"2;LD[HUVfMB\} `(=US-\CD/ʩ_C=>gyYtwd_X$؂ڤ)j=P!◁N;$08Z鯡Uн9?h5v5([iCo H"}วJzG*{QvN2 |1_N  E tmحtc2KMgЂ2~mR6z2 TxDr;6, ]@#&[gT;c}mOwo@.|ZWЭՔ[d2Q Mֽ螋&fi4)&27"NYAĭ1#pS?ڥ":.(x([k)MzȺ6btb9O:= fۿw> 1fE$vaQ#Q |Yl3'_Q[};6a3 qez=[v٪\nr,rDɨ5M:l$$cjz(oEb7Î2D l"lDžCgv& kGwb(=mm3)%Ak+++/ WTV-FIA)ue5Կ%yoσTXZZ::|oYVO.\xFZe8pXXX()8H8/Ԉ9 yރݴIﻣg\]MTjeq*ju%2saz"sBD: 8Mp9JQՊTDQ;_3 8:6Tq0 qx$N( ͤ4kkk ǩj:'¨Wnu2rR3_^Vރ;qFī3օa#"r#"r#"r#"r#"r#"r4&t FUFDlooV;+}_I$N1ZW,D4cAA4.Lc?&"#A2點=Lfm/^qҥTdjz?Mwx"DXZDy|۸ÕRcI333%0 /~&@I: s`fffI∈ ">c`/3._\γ&Ĉ1 ^^l6O(wu$Fĕ+W)6RCSSS7 SVSټt2;;{f_XXX($@~^paJDF<{8==}>yCV+*NA&hMZϓʉZV pRDFDd\.ߛ|FYIbqqqT*|177&[SSSf yB|wzKR 3N fl4?~fX|jz`zz~,--QJt'>fz~*ӎz^Qv<ܛ)'Yv?j$}azoLa)6?;Ye׼ cfÊnݺ8yϟqFU&vpԠ}u]y8T 487ϟ?* C/O3y1AfcL^ttfffJ{1U0l=^z~*rl+qP(I"s"zjV 8m[Ikkkv?1"7oN9Sq]w9i'q9uz!D9Iq\y^ ykAVPJ %w Ѫ+lF/79,rCz3d`AEnHe[ɟmfP4pfsjZ̉} @PxfYw]5Ǐ8l"p*Jggg(D$vj#x/ ҙ TJm.//d_9^fUjPJVEB^.#z}ܐnfffT*dYodhh4ǶW,)-+W ]WiFXnn^n~#$`z zFֈ y~Lȇ?7!E䚝֊T-IENDB`ukui-biometric-auth/images/Face/08.png0000664000175000017500000000756115167732630016452 0ustar fengfengPNG  IHDRbb8IDATx]lYVѶIvI&CXș&FZh,O,3/ OBH7iFT/Y" InGx0$WpM߮tmf2vUݾϹ޺UDdXD΋e:;<w!'#"2. 0.?7]B<"򆈜ɨm[-˖/ ȸ 4!gl "޲qYWYLj;""8YWYuEm:"pCsnK $l#)O"4xӛM|eٟbpq;/5c.rpN6w_')y"nI52DFD\߉@lJvۦ&Q!#"v+6]v59tu FFWqtRo΋Y:h̔,lƅ\ ݙN>NJDLieOi;j43/l"% b/n=}b(ؼeK.J~^22Qݐ]d9'/Kc?i)\}&txGD=^ȸυG(t` \,]ǦS u߂ۖXu9Ih&peD  "(a9``Ht| h&At^"A_3$ؿ|e"iT*3o WD m2K44рOQ"!c4hGwt huq FDP4?G _A8 ="aV$㛨1Kk?ykh@qNe#",L|:'  |kFd Y:!chъ?`5^:"Qq"$ܑ%-0O'kTyF9i24!N4b7ڑPGp7gu^?Pt[k| v!;"B>D ?~(Z׍Vcd@ F# ? AZ`L ~/X=PӢՖZu7Pt<61-0DX|M'}OW^@y1#<~U^7M温4=qm/ϡL/F}=!πn5fNc[DhzhaBN#:uԘ`05RK(a46Lᅦ2;4 uA#:wீ5T ?Dmr~{4k=j2-ǎ` >N)2Gre{PsUO>FOuXE~K4{SmP$1Z:05:@Su"#", N ?A5"m`e~%P&8IjE^Gڃ#}P5]~x:O6-l幙:D(ڒk`͇!ձM9Fy+k(ӵr#?MiY3Y~ܧ1d< eh65. hlO+9ir؉F6;> N!dvXS@Q){ݸ+kOތgSy"v>Ei!:gm >h8 . G !n[ DtPyMMyɀfUPmo{<~^4wĭsRnk:62Yz%Gѣ]u벣􍥎=wRV-_w޵ͮogk8zͤ٪]fwvŤ sss{mO 0000tYZ;ti8BP>7D bnnn;K%"#Ax[ #իWVV^~0 ג;k}AEHe$F8qɓ'o'wP*;T.DU$pg'Bx Ԯw4"RI睸y2D:yv!W^Yiy@mK4EQT޷U*N:5&ĈV^Rp'Ĉ8}CqVMm) +Au\ XsJkT*wYu]whbbHyg颈H@AxǏ~I\.8s8 ojO*h*=Qz:88Hޓ W^_,&"LNN|˲ FGGG\m/Rt/oK!Ax/bUZ677waa@OO>J͛G9n811ѽ$uÙR^\.c"nסkMRaEnG e"5(f=۳ghE8׼hq(Ez֭Yʮ8v~w]7\YYz~Ǐ6Axp]Y=155U_ZZn("/nرQ놥R)9L_̞ۘW2U:>>N{lqU(=k{9F9nX(QN9SSS i ޶t; WqƨC&fW9Ј 㹙!D9I""4$r8NVi@nw|qV^Hc7n" =C0 ߻[䆈+++*z'wrA3EQ%J 6ɕ9Axa( Yݻwi6*=8+.pCN6uyad~ü`[ߙ;4>p.Oރ+/%^@gK .Αv vѝ1ڛ^މKIENDB`ukui-biometric-auth/images/Face/09.png0000664000175000017500000000750015167732630016444 0ustar fengfengPNG  IHDRbbIDATx_lI^?{qH*!Gp67!H{BC' ΟOȾ !A'PK(i:$,ɝDd/Qǎ==㡪25gM+_uu[_Uq,"s&tkk=.+=$R?0=J29yWD.TW"rvΑUŻ9!k^[;DK;6n&n#E%"RyguwFݭ;&te~zf@h$5b?>>DR^?/"D>-Zkv{c_tv6pQ). VS~$,%nquJ^ʿDn^7яZ2<ّ4632r!b/ܳEtG@hcك+Eb}7\ȃ9.+"2E 3qM~tJDBzֱ]En\ Ex>A\km{WMs].NEDC,f/Ȣs?@7 ̣`5wM"`aIqk3h"$, 1zNQවC3pWƤ,OE vĜ;'7j?Ъ툰ns5I&Gu;oM_#MRR%BDfymt}/o+?Fh24]1nOiMm`1F ^h@k5h3Cs-+= +TB_1֜lot( 9vClǁ7e{MDlm+{҈C&X:'h=dS9Zkh{"Fo4/q֝rMN/+"L3 lODV"6i;[ l (h󜟠MKBt֎Ki%|\\yфt陈X" 4f%kkڑ=d;a[oۑ|&?n [+t\u'8n'" DPpX(?oINd&6cl%mFL$l>5-Oc 'uk"$Ob1Ve=*܂ɮm`%n_?M[MhnֈWpIlp3Nkёy۰kڑђ]ZvM MO ""H0VM%FFت)nz?6aV#\2 V5;Z͎59u':[v+q%Ā&mhk WѵuKJӚ!#;?YYi}j@)p?اYsJk׈?_$MJkR@bN_Y*!mvfl7`; L8L swú9nmX5V[Ò~+CBVrr#֓c#&ΆIw9Iڄ$۹$CqBDdcYa獹 xZ.?4WH[o b؎B_-[XX8tP(Aӟg^pΝcJ7<ϋw+}|\Z=EQjZT*Fq@D>y8{8䕗{_E+l7;@D6>{yʾ1(ZqC"2y^۫\#\8ud}yO8OBlceey''O8|y^ټlx$ۧ)E$F ^V }ǝ;wEQtX)vݾv޽]_GJOT*9qʿmDyUh^bZ{!C_5baa ^YY4]v̺R baa@V{.TJj0W\TJq;Zŋ.g s";!yaɠ0ǣ(:&"CCC7oMLD}+1׹f \.?{N?w\iccchLy^EzPH*IB j~4QTJQk^x!>2`B4Nc#;Χ":){cObhe?'@!Үأ-;Aʬ Q2ǯ !_RȄFpé*WHʦ"xh76?e2SB;/1hCO.|a$,0AV;/OflʿD0 (W%2$v%il6Mc,2CF*DW=[]H-N6OgRҝ&iX;S%# "{Tt's\3S'І-#ZtN-S/L"( d:l$e]dq)CRsH?G) QYxYZSOLLpI&}Eh"Pi&{ , *Vauny aLE:Yg,ts]2h%g[(fژ[gR4Dls]&ijiA̅@q [x$HZfҔ&x|po87N6gM(5mРưtɵ(v Qܝ@&1k+$Ǡ\ӭ0Ḷ$! aKCWn<@4l<=ջH6vf+馎xذ Jdms҈9~%()]X{[2Nqz֞)[]*-\DNfFys[ 5w%_9;i&8eaERO.ga✡z"<ǔNp~JD9"."*p"&?ѯh?u"!N7&E} Q9f@@DO<}MGx|/,s}ys||_xxB/P&巍#"3> ".J;("|$lE-{ %lP<y>#:w9sYbBD%\> `n.__ 7T94@$l39"1"([nB G'C&0mE>6M֏HEs@7WD |PҔ"V"o7|`>Tõ4##C#N'$A4'Ԉn> &رB WsV A UM[sCaDts^hNBj:B ODA-숈ZyS+FD qh 4BF5$A aE4j5fjܮډl"ʣ94SP&ʜCL2@ V9=h$t/.~=l&k!aMD@ 4zbAz/z`>Ajd||! U94i #Ah:yQWMYG EFTh&!_<5aDaj8[3d݌ 6c .Z t92-DH0$egB̛\YMDp2c`sь", \}P;ESٺ7LkZSpA|8W:׎se?@FYFFFCuHDIB~>!r-W< 6-7]ZaLaZB7ĸu>Am%(X0 -KF~}P^nX2{)jQҮ^AEN f;Zmd.h9'T3.0'q5@pz|j["HCpQ0A:I\"o=4ӴB P~|b nMf6Pg;teô}=piak0ڡi$T†5n@iX5"ulZE vqm75P(/ Y-8$Em1b&5I DU>u_3vij|i"tO ZL>G^^ADDŽ,z-p 8- 4X'NH|æ;Aj_oBV,<+.E>o&b{T8ӅݻwYy߫RJWJy+knhq'\=FD\յtŕeY===Zc:׸1KҭlqǏ׻^%RJuݵ|>_%X' mXVW:=Ɖr\t]w'84T*u5!ĪmKI/Ҁ+;?2==]HKXq:ٔ?HKHJsϟJJ,Nq|AKi?F2Jˏ}x@Ήw4>[Ohΐ`}7rp,.x&‹jv#JvL39z#^{g^+}I{D.%+rB#=GLcT'i.3YqD:Ӳ5 g6紿O'?ƘЏN?Ք]AhM< xA^1V2KjH#PT#znaC`.$X(A*6 du&ݏ%Bǣt d'h7;$4ڭ{t]h_؍u=!BCWH1YֲU3zX>*]q89Ĩ[FaAK H,/p4x1nދxĿMxڵџY x禽viY8XyU+-解Yڧn |;:}|>N\"Gygm;_%KI; 14 `&$~^y 6(cy W"rěl;-vI_]tZO{4f9[А~,Vɶ]FO}iקmř$ӪcXLDaE{԰s؎r}ʺL{_Ndi{5DiAF\X%E+Dh^ !tx^3mEVɮij 6,.1 &[9_ia0>l+_X-QeXҿ5Q41XC@S*f%B.ipDŚ'k? G҈=5}P?*pK6u/5xw? %@S-yl ~H#!V'Oe? `MipK࿱`G+XѶg XM7Je bUw\gy hH[DWhN+=~ ;/cM:{'s#\՚G'g_3n#b=K0uoG~Zkb# .|5-^!5,!2 -pD yIR%a 1 v2'NK>zga8՞:#r'?mɑ_pEd'vD'¥f8""}Św)W'kDܥ9 cu-,Vkd쓐~w `r'ܑ ⛬dyKayYՇ(% ڌ=]zY`[껦`| W|Sh99s% (pE#|P4"ρ_^> C aMmʹB#X-raWDaIhdj|Hǯ]<7 "=v宜<_jyir5Q3I(n?^L h\/'5a8uְ6N>Ѻ;qTj?{<G%P1'4i>鐗kّp(AOTr(/b':M]F79d{B3XmKKo{BvZ~}O]2<$~9y߯$"EcBp%0D4"]֣( D" %b^VǃIt%ک6uJR8vA{KN8ڵkc^ wovU@ᰴt,Bpcjjj+϶?b֫z;϶խ~wwjDdVb8 ]V1yj:EQ v'j:֍{t!bkkk nCSax8n10D nݣT*m"@QVǂ h@juQT aNJ[ݼF!1h7*nX~j5 7^%qԩz^P'{L?:qڵa17zڽqmcc{q]!^ݻZDQTwɿsDR),//O8ݻ~/IYJReFܼydEA^|$@77o< sclnnB(ZEQ~c̃(6>|w8>82::zP(vAA CW*ǟg"T*mo\re+obr'bqqqP(j~pM׿ *J_{z 0 6ENs[.Dhdw677zmwDZ ƓϙM#_>&0 1Fga>k]M'eqqq߮_?PT #+1ؿCB6=__Z5_&!||)(]ow8(Ё\9i#;DB"JICoy!_{?Go.ƦAIENDB`ukui-biometric-auth/images/Iris/0000775000175000017500000000000015167732630015554 5ustar fengfengukui-biometric-auth/images/Iris/16.png0000664000175000017500000000640215167732630016512 0ustar fengfengPNG  IHDRbb IDATx]KGzqBKH$a D;  !cH@K@h VQ  0F ^ds^&3XԩSU}sRw:uGtHDr|L dž7"BrDrFNȏO#+C3w_:%V1<&|L[Drh(̦gE7HttHd#!҉ѭQm!H8#HkRb2Hmk,Ӗɵy'; S[JCn9+(# ևdD0sU! ng,;Dd1h2A*!]uwwo8a>@vm-_VXV3A H}76u r@j7I|m %˞!dob6YrV7ht*t}jKQ}[Ǻ'Ƕ#SKIن0W^KnK)Q_*SY_پު(lQbByfMe>$[/%be7{̏dE(*fWﺪw ,r8}g!3uKh2Ry"7t:zj/R(vih* ><#pc#0`jݍ(zɖrt”}]tb:g_~;i:3[L [/#6nz, X$tT>em:yfՊhѫSs]R5ĥ%;B2m:30y7q x7cIZX ل jhg7}Ql6̈́XaEf溪#uߊ:,0I#%]hGmߟ>ۘ`T6J*Z~֙wե 9,*8PոFl'+]]]5fqL}I9 FyZb« sK d j]BWJ;bj7gfW$'&kn,c_hd񵲠b쌋V&L:ݷ0fGHiVXp'_j,T"J5]$&-ja+CVݠ1S_boZXjݹ_u櫗̃Sksd?̿VSWߪ A]|0_0qc>=R&)[Z,yJ'Y,MH>N$O!oQ J@ٲsJ 4b>eみp Aiߏ* 4>1 k]v,{Eo5s?'pР24(Ky,~8Pf hAj^}Y1^NDG&+*2wͼeupE9| /> `Km5+G1|G~?"!0U,vX B(C*!<0eom?(5F <cae@BSBL I,/ܳ ,vdjpx=x+L3YJ(~ԁᰊz|𷑃#v@hЖ:_q[s!Kŏ!~U.@} auW)%8~L_㲞^PP@1OYC i_V` iYw¿֖Q@ )kAEV)!0Uໟ|a0s(xڷ"B)|n=.UAeA?P'h7*!~wx2"=]#JDIZ[IJnaoiد`^QO(1-EO@Mk~ȏ۲+=f?5 PBϊfJckY_d[:ꑶ8=Oa<`0?s}nI=W3@JgC."7x?a䥄zR)e^YpwߕLyfM hM :ˉϗUo$Tiv*o-f7!҂1SHIENDB`ukui-biometric-auth/images/Iris/03.png0000664000175000017500000000753515167732630016516 0ustar fengfengPNG  IHDRbb$IDATx[]Wkf2icTv$55ŚI >ħV땢 >*(i}Ѵ,|kUD1 БĆL0LNuwY{/g$6rn7l`XE丈\p>^|<*"s˚ADn"rQqpqTDnD~-U+&*"2x>A}[׋ĩ4zoDGHDLȌlYIDnmˈ-ww>kZD܈8c 5f !s%Oa6Sw<'\3b p՜_5ܵ|Y`x9iFDM}L$ʞp^F RP0H@) yϜx 8{9ZCgDaq=}x9 dLST%#RkR? ڋ2MD>EIC-a_b[hyuaZ$܃DQU!#.G)[CιkU^DD$< |_(H(!eD!nq z9z8\ZP4P0c KTtKF\IP vw%sj*D-0|:iCF`X3`8LM` VBsK;+9EDd| _mSL6_uɰa@6$!!zwkgQ+} Dk)Muɰ!!$?EDVx2ǓUDȓ_Pp$.y$̏=^MUoc|[z)_*{/.3lbl"hϋIɆ)B~F$^1Ͼ°U oH90M˾*El_H"0j!(f7|f7i+ԭ+/6?3zlUR GT_3r .!=)a$BD#j%ęYK6XBv+|C`xpAS~ñe|(ks^)R5Ӟ& Iۦ{؍*t 8[;/ub}$>%OZ[K'͇5u>]% o^PR^M% oR4꨻ x>t X IΧ ~ Լ/nT?YTpWG E%bGS_sۦS3O]ڷ0+3]IDw {=(|wE?-+8υvb[Lc$BDv{hܤrPov3%xBVǕqM= ""7d$+eޝɝ81i4Y34zϻ( 0i$"[;iN"T-枉 ";Z ;>˧sCW)|sնiw GᬇH˺/kkSv$(/U%6 R9}mIZШ(; !ᾅi* sjjfBh^-G^gZ%=QUNQq660Qĩ2ڰSOp:xnEdn[>[q8.](*3ч)Bl7i/'mie✻,"іVisGU[]"f;,ЩuIBVTz Ggd%"aVsG[ՐwQ/W\4OA >J$AME CNBki/2ȮTh4?[G!")B&8\[һ2o[,1ZNDB/^3Fm2$`QLр +$e<С|y7ԔƷ6lԩfi"@ȩshhS JG ԂmS [@5ua) jEt͵b~S62Nѥ蜻fI*6K&0)R; YQx YMLR봄; 5@~`7:&#u:r J]0!\@p\jJܰtVՄuC~/B3"o9 Ac`Qrc\#ڙ ujgM]G1 H[>ti!#.!GN4WqM6GNH=9dنbvf @SJe|tdޤ_:"k:a=vV]k7/]hY o9̐<;ι{STJ8LJs?o45qD`=54[_I=|o"pkM1#e/ZѴu$bWXF,|%)Ǻʜ>,LbTgl|"=йG_)5I#wMThv|OƘW,S]}C0EI"|S"9|^VZuYk1MsQ}7xΚ6ƤX=K!:jҥ]0N&_T9o0H㹓&$r\9<sa М|pl ]0$"k5b9AF`. &R|5KxAIzm4! Kψ,x}BFf G'5 ~uQuk@DȤ4%qX7߈Oȃ&'"r ~غ0E{HuJ5Ck-(CB6GrGCcT;BT.P.Tʎ^'C"3j" FBE+bb! L*r401?7lp@S+a.\IENDB`ukui-biometric-auth/images/Iris/07.png0000664000175000017500000000745015167732630016516 0ustar fengfengPNG  IHDRbbIDATxk]U{f:}ڑJ, QC/-D?藶ch >M &'3 &iKB@k+0C 函vϺ{ιw{}Ls^ksρyc=,"Ddrwn1ȰȄTc}1""ݐoKZ("U9llBDSYhʛ٨7`\iZɝ9ϝ1D1r6hZ؜pW"a %dZGe*D4-3NDhz#mݖio^e4䬳"`XF&HΓ$LI/dÒםdu2"wԻ!\ 7%|+!rS퉦$mKg RW\,ly1|x%\pp 9VloTD'u}\$t騠9vkMι_rm7Fkm[նжg. NZS˨YO97tHE5iJ% SGtبx(3s 炶[ҁ[FIGmg5usj7X%uTf?ƺ,K(ɞ҅hL ) el$s% Q7uA-B/B¶$6JDȀ,AY$",Sqz~qQ]Jp̽2鍪H zvРv9"Lx2$" Y)"Z.SsW赆KEeُLHХB~+$V"21ہ@̾ }p `{ ^`P_ڴܖ,Bx?,9Uwn?~롣-y% rڊUP, 3 |E{ x,+ ?rݟA h qVcoc~|߁Ѳ2vٗBBwCϽ_+{X|ߴa )}U -!}f׀o;r o~ JFR+dE%0e 0wGp]}z$ps=Vm1! x "` 0pzdq"&#nGH.z^=! w:IM!~0 `ߑa9|{/{f[L_JFYA6}GER OǁL>0']Jf f=X2IaIcH?idѺ^cZY:?&\|GgT[)<'zgS9k5 & ` <q2k+e`/>|j"RHZYt_ ?AyoGS###< :5&apvw,a=;E)*PYcfL o~-w? I{(sROzIQ20gO/u"`)KtyT-j#|gn'l̵µC F#BӾv,7]+"{ui%< ~>W֓7:'o]m!8wM"ZnEtF|ZmBB68jER->PK:\oY.6[MoοLͺ] 9[\o.AM(>+e `-Kx .gv32 | Os*EG{YqCIZGۗcǔpW+t|jY.6^d@D 6x_H(ךK!k\+[׈?V;V0x%XYּm;c/g dHM3,LFS)q!?E UmEz^mLb=}B|}yz`ΞS!_!ǎW!|x}Tȕu4> !j?/Ŀߍנkq~_\ESEfء+X8%osny 3># $㣜A~^ {&~J=v=L]Ttb|.2lϛ+vN) &x61ktyTL934^ue킓U+A\ aܑאMA[mEL:aVWڒx)|{.tιg˨A OBPX4sϑ=;$"KD>mme}q 8;ۅUf}OZ3Jq7R:f} xH:o B&iskZEb|>8ͬuVpE2kU4.E;Zΐp9Y?Ȟ(0l=vNnC$wJMHrT56n ݩaih$<dj ,l\C35&$-XFqK9 k&0w@g\vKj " 5574D툩lTsL2MYkΘKԸ1dh '*5PG#8:jl9%CBUHԹUdn*5Ϙ4L<''nȴakPxM )7: "(FO "tBVWISDdل^8ri Mʆ2vsG,&:r;ihTD.&&$w~sS">Lb$"KSCG^5YO\c)マp@#cK3ϾdԬT]պ9&;L繹V_uu`ʸ2%mcOd`50U 2VwnN;%n[#UЄmYƀ|r'Kq-u˨r]AudԴ5EQ=N$>vb^AՅ.N_בYx 1]?>\ijhgfM 2k:R5è gK*:|Zjk >S/~iD@U2Y2J3^NR"J%fChV) |H*5dY*xwl.hYuoݒGf.uks4[^B|bNbʂw%3c%7v;ޔwLEHR^ wل@ S-ʴzLe!Ƣwx"b^`}O ~v8^鑥w 2buIswWs0oZpz"w0e&QP,zj>nWdQƻKwZ,+Kx~|g?!XqQ{J!"\$ԷߡaV` 40a`IJQ?t4S7Ƶ,0T@tdodA H^WDokKsFYU/%zuC˜t=8T9;[_1H7:c 9BX2^qcFGUa:~9ΞhwOg a<O)egYAo|,?{/6ρʇ |w͙֡X74VPS9G2ףB!@X/")n(eSf6]C"7j" FًvDB^.6vK@OuYg@|q&<s A$IENDB`ukui-biometric-auth/images/Iris/06.png0000664000175000017500000000746115167732630016517 0ustar fengfengPNG  IHDRbbIDATxk]U{^S81R\EUS@% JBD@*hAI $h HU8 HE?8%!VCq7n38S1qJ(kmDm'tu[Z$`{q&E;,=і92n6՛P'\qVP wSO± 2F$jd W3 "r]<)ѝx Șe$hpc)hܔ1W;C6'bM9GƂ=,:;yեmJ7+΃dҐQ ǻ ogM>/Ӷ-!/TPs!RQgHfGLb'#vMm۝[t(6IǤ<_EA>>$f5bpQ3Z$"oBxgӶ*< <|8\!\oEDduQ}YӔ㨟 $CNn卿 e@⩁^}j O kVtǁu90Xȁ: 1 mgs')::nfxmmG?Z?%d-Zy9C'P~'+7MH5w 5V69B82K4$Eti߀^ "S4ڑ'))g'e$4%#m "< {$;W'w[K!G/D8P]/g0>Nd#b ?* UQb 4paoVi : \>2U1b7%#mT|>+x7h~%$⤕ysQ_"ŀ)cğEA4ר ($`ae@a+>G.SdEhl;~"&\^~wue6lMD$V0":p5(F[gTq"4%ç%)s 2 $ꂢCh܋%k7),bk0fl2!~Ӯ̴5V14^xKL>7%#5NF3묞{oPhx$d5V')+-c%'vd0j=NP;ہ{i6s(po7QB6:#'d(S\oYABGM?BG;(\VQ@ENWlU}%q#ڨ_^NMߏo46 73 >AA gO"?@Y4x E{bgo)~dF ir, S*ϯ Yѥ j;h|j>ۓJW):2u7?1)kTa8ouG뜠< gf OIͷ#QmD"lϣYTt=}ܙAo;m7Sh݌7*Bm;_j:_ړfvs; Z?fBD*а?~;OP~LDƤ;iYa7:.O]au4cLVQWs&CHmzl4 ӨKOtJ>]A'"'(|vD_ Mq#J>"e+gmqt]z'QhS=f! 1}=MyF ;6KFߩ[♈6 qX^pm`$Dt=&S ,0frԥ~p]qԖ ݹi騈hG;YY90 aL :XFqj Y59O ,N'wvKf UNWN[&unn*jxYwξO֊l=JdD4%# #^53 gs"m&? qmM3q7 *6ZXksDJK]u]O"Rѯ}b2#4mc;R2vlz:p8aV*B8y_Tkݶl')7 gwRWT,]1z̨"sW'X5) @յ.QXx.|{i@Zi"+n&9%%NՕonxOf\}0%:a;GWёzo}?y ^h.o{¨adGeLf%T68\ühJț #`/zU`ThJ) )Eҕ eT$!qninQw|:Os!Vi hz{a7q~ܐy?<BxmUAGć*v{0 j/ Seڅ?eL'>dq}Yq*8MÞZ56~//]Egk }[Eu_s?g 6t;p_]u=(>Bx{_Yu bɶeZc&k@qK!1%E EWVw*zEʗGLFC \}ˁ(e3hs.ZqhYN%VZ(.f6F‡{se,+.ݥ#Ż宽`x=^GDݔls8eܷ QeN67MmA8eoQOgÔ3ѾA-)si4P!'㪋gf$yX!FDy8@dȈ/XFb[eu}Tv۾PC21v 9:淴ԡ”ŘYh_Q? 1+qt[\W-ƐčzeHQab1Wőq1!"c9\kkhy IENDB`ukui-biometric-auth/images/Iris/12.png0000664000175000017500000000670415167732630016513 0ustar fengfengPNG  IHDRbb IDATxk$W5;dlb|fVA g!*$DA((*fb"H@$QJ5 &$lL~nݺ]]]]3ꮾu^Qp4'iYR{|$%/iI ҁӂQ3t:lV1R-XdfJ7ƙG8"I=,2+.C [A/64.Abh橐X̸$EC٦ݪErmmˍe.i0!-(;MKv,녲0J]TTu(iC`rV93rc#\ D%֎ҁR |Ś:WV۞1Pչy??Ķշː:fnpVvQFH٬p1 {iS_ǍʹGM\("ecAW*s\8{-$J!3ry;j/R:c*X4>Z=Ï=Q2?B)=]ܸ#5 ޥ|b)xțF}M.r ^r@w*WT+)1vBpk򢌲n0nȨijM][e`DvOsʦWV+;e3R: ] T`6Qe2Ti=Cς+<`uJ5+s޽ުSUɂ8@e0V? X=KVGmJJgAf~B0څ˼|uQR)u9` 3L=U6ג*t/Xlɼ΄~'n"MoU4/(\PB{˫~(\~{~3I[3tG:io"#C|}=,ifv\<[->4snn& w4^`*t\*kRv$JUc;Իi2nਗ਼f/s ,W{,HY! ܧ ԶHȺԀBe~e)cj@{ѲOJOKvO [ӪKY:JϾJMҋy.]+gH:[NISDěgF~脤:<%i c%] KtIzgKP>I)h+q*!ˉݣ}0,88mwwV픥ǁoX[m+{*i"Er1^Ҡ_@haP*a m_o'8a}L}Q! 1lX%a]Tn d-p!vv{w! |7p?bj,ٵ]$Mƍ#}eYFy1I߷Lobok׷E _ |:/= |}>߿x:$ɺܮpp8Iz1Z pفQtr13+7YR{,=K?X ?{kkֿڽ+@@nNk~zve1xy 6o_q ?a * pͳ,T IƯ'qŸ"k/>iZF70&po0:&k~|\|xw;QQ`-Iblpj*)! ~_s70&HAHL8ʀ^X&K//De֒$Y!J1ƒ0 qB}3N {7r<+)FUz׭p.\ Y| i"r(5yzه>i҃{i+i N6v)BnށK,%? [s:]TM sUL!]vWXL$}^P`b78@}k? od\Kp7&KQe<'2@H8.WTeopXlmKwc(!z{x n0 |-|x.7>皻qEu5.>ˤ~ne_z\f0 :"v .}2meWmLl{vں񶛬K;sAm:5kE\&zVC ¼0ۃnz +I<5`}=p`ח]viv-v /8`vgO'IS89QBJ]KhV'@ЈߩV3[ePORnR3}FOScFR3Di3"0ܘP𙊅2 )rޥXgC${ Y)kS}cp{+ƍ _0;~8:_8M>iPkrLyS9rhkgr)^bƱDS 6n,OT4IO,[ r^1(\Jlļ_[vxhH|KIENDB`ukui-biometric-auth/images/Iris/04.png0000664000175000017500000000742715167732630016517 0ustar fengfengPNG  IHDRbbIDATxˏ]G?iۍMll`p,HFi$lRɰ`mlX 1#X!!0#3,w'ƑiIcQuΩݦyܺ߫ "OE9r\rie "y)838/"M<[Q/VLU EdQ\ǦYA!"vĩ4Z"j-R-9(!ZDi]\JDu.Վi).5.D$hwGrSDvN_P "DdVDD>"r@-ۯO5+"n5ɾ\ m s_x lxFΜ]̱k5wus[e,p?sGщ%aY PLJbh992`B8YQ8w oo:~)&B`$c 9ɘjhKFj XiVJB|<“21JƳ&49s[tCoCF\+%$kE$"RT@HG3Ֆɘ#7dQOJ2zaI (!9]5S;~Фhvb `mk_ XI7byDĤXș2BdajH0!f{x %D\;秜s? 1O8E,iUGxo?Ƿt{xSR-4bCI}9Ӻv%BDAYU;!dY"7CT^yR[L}GIO!K/+xVNEm)d-A>q5$Z}z6`^Ǔr_';ؒ} :"B8kXRuZ0I"}Eׁ7H Y`8{4:WHoDpJ'vgC$`>:u-|xgɛz<&GM6d>"([xBܠs.85>!eS&Qo7kb_ӊ <}0o~7a9IO5x<\)^25V*\;|\te<!A|@CzwׁA&"fy +[=ީԆk":.K,Zɦk{;,~73c|8\Bz]0$bIJ<m%2qg*36<J哺wΆLٞzµ|?i_;Si*_/LgjxKsn%"WR&~?U Urb~J~iJi[nQµymp:1uzEbs}KDj95♚1[gkӦ}XIpZՖy v#އCq= M poR^-5Ҕ]w:p9F{oCBDNRu&_v]K뺊o^DQU ^VsTgF&i#R*m4f!"ǨH͐ -ws+Rl.˥s]"rOP3s\OGK5ZG:L/aUO5s:~X$wk"t9Z&,8Z.]A1JJ9>M8nCK*1לpDOG)G8lx&]IҌk 9~bm G>`/]זa]J~O#"rRD⁽RXm9᜻w"4-QjIPS|ÄomVڋohd *4kzZlՉ pD)Pm %V`%ߍPZMDr/^3_Kvr$`2D~ZuVxf ǠA2UDuiv-x(@+TY Zc< /5 Kk?ID mzi}5DJէYS_sO6I]ȦvBF`ZF2ƈ6:BTZ4i9Цkk("D$BXFCp$~:Md}b< sI[8iWYC(t+|^#GF(8~oPp͡z#D$PXhN5pe|}ʌƷ6>!D6vs8DDi΀^s{hևfMs Wgt2ĪI ]mlt5d(~jH9w;TwL"4lDmwp@yɣͩ؜-"ڦ'<tkSO $P7;̛wA BC$^&D$,r qW̥dX. K6y({/mUM8MaĠ_M)jhYRMh k$L?3$MGsh1K`A:ik'$I!CF@[2B5N<7Zyj!iѐݲ$@T~ƊߑQaqHr~*)n *arD Px aRd;ţZh+].y%vEr%FS 'y~Oۆ`D@yu[AYyk[d1 ;2AA-|xή[%(OToHξ3ze^ آPgFT=ᑃ]>#VE^;ZΟ%wFbT+IȯZ["r>/-yU ]f60rGGb;+y ޢԾMѦaPMYe\^5ke;5)ٞ965Ƭ* t7HmTKq&N$]#[Gf(g#{i^!l׈ET89-$H³ۖo{4!QK?ψ,,2O0s;;B= ?<NqX߈`g|,6yv~PB/)jE#9R;kh-!ʻϑ P|g?Qu'Zl'ܮ0CP)h*xSs̨{ m2\<1rLJĔr枖ܳ=a]t̓5Y{IENDB`ukui-biometric-auth/images/Iris/02.png0000664000175000017500000000771715167732630016517 0ustar fengfengPNG  IHDRbbIDATx_W?gwۤ &&v5ؚ*S[|ZiDVmQPhkZ H5VIK[!1&$6$fMws7?͹3s̝w 93.cE:ep.|AG!"w˼Ki bh C!BDƀ =|<~x8/\8榐~ K5?_fP2LJD _ި/ 2)hJF*", 1:{o=| yRݲ  `#p/!}]d$MN1q>ʈC=K1RҩYt=hUxX xLMc<)cu*q\Nt>ܬ|S0 !06`/k xcyͽ%%SJE$/#Ἱ5m}: i sjI$^=/<Ed&d n)hF>w>nL"{Q%aR `[`|L BKD-Viu]2,RHv7<~| ~<XLDD$KB x ݪ2I)%$s\u=xUuҗ$" 6{+)*$MDŪ~TK.i${Xp+\=!{Y({UfCa {_W9E")EF=& wRz*yz%/&E nŒ*/ ~dKDV BMd 3EoZc7J ̨=L-c~$~{Em!SWLKD<<=sEA*lFQƅ(\;8s|%`*"=ιDd-`ט3z\P㖀y|7eNj"6 {*|%"?sΖX YWOXSF_szm:"O ps岰Dȍx< LW}dPhـ/>ɤ`0ث~X22#"B;>V'[79BI6Y[q9q|<9k'sl ԀҲ,$BkSs0 4/PSs)^3dn-m4婲g#qνBB&-YհFhŤTmHC@9'%|k7IvE`F$^t`cP >Sz><[u0rPsjvCDd1PeԂ-uc\F5ua1 b҆wM+b~Swզ+K9w63du&E(ؤ5MںDCcMj'"Z%ZK@jWWۘ-n&`6Z&#uZL| BeN#šakw[\DqCVu=~*3dD5.iPT̥N`% g8v'5`j*: &ζ!Li$6ti!#.!SFLφWF#V9׷rTɈTj;cּWN(0&^ucGԖC„뾓 2نbr&VPWB:u'ɴtEt%zS[y<~O݂HNju$8;P:\l|N[MwIH"m F3;)`DM6WɨTUzt ~kŃ4s~uI Q4Ma%pnn7QYѼ5FgP;vPqMA$2|v;[EPqq\גW U?H{gE ]2Z]t}'m0В6K| ]l HmVj:x`7^^ L`FD;jiŐU|K}*(0^/~fPDW,ZV(i+M"s a<2f٭u "vޥJ^a栝!7y+UA;N$ ^)"j;i-lo2|wSx[0cgso/ SYTƀ K&70MaZ!@ ,n`pUD$o X#QU;m݆מ),kA>٦!Vt+}6Lrc ,Sagy5~ ~esf했|x kp`U0_he;#aa?~];K{z`4 xRR_֓Lh6]l|9~G β6$[ 瀰l(ESf*ӺJGDǾV?|ADr::iI$4C"#A#Z/"G4ۆECCpe22h ̲`"߭ʯJ( A]/$$’fMHHzCƾ&f!"{M\^Lk= rdo %g7")8#V&D6ǤنU+ "r!_WE{ԜR:h)(C(_mwjՊ#DVJֲ&gڐHri@E bd.䝋[F@ qZv_ҵ?l2.25kɬIENDB`ukui-biometric-auth/images/Iris/01.png0000664000175000017500000000603215167732630016503 0ustar fengfengPNG  IHDRbb IDATx]jG$$,$lgO =A'p ='0{{O /+"4E&!1?隚I uOM(30^ z+{w[D{Q⦂a=f>kY#%3mS3.3((]f~܆\ A~˻6otlH]܃iȬU{c9=z5NDDͻWXϹL\UcIsDtU0mK/ot i^sF,{[)# )V&=bc"_Al`\*?k08)]S$f 94kY"?pՃiM 08NAIn^mf{1 0w`bƭ CHRe#9]0)Lsf ݂i_7!Fc2pc(70FL[#uvO?n0r'U$DoaN붭kZ'AaDD! pL0iaMd+[vJ0dzL=vUp4 ȯm=":Sn\|ꍒ) @#A:Ul뫍1L}l{JDt]X݋~d XR|\/j\x&J&B:&vqt~wyE^k̼!-8vA#C[ptb$Uqu!e>C&Dţ63/Y13LV 3/dA<"y @f F7C~gD:fU`[niDt%)oWx -d$\d $0c e0dvQ`/A|\FD/%"K.a,!$^)폸ڪmH2ǎ c!MNfXz2lqGe !IIYFlK." EhZ֠c=&4ʛ+#F?% JBVcNuE]ڌ :kk`Lz%c$G)k^a43&x U30)#DvvT ^U'6s!k[sTGƦ!ؒUTLHT@LdĐ:pXĖcoWt֊BGX>/J iA9Ie~Yjd0haE"5禋z2d*S%y?:E@XN 1SrHj;a9jG[Dn9G}XitoN&Cl3I(x*7y`gW)S5dC]":֙ihiT kB5EHʪGé9`8_NqZt:Pa.1 $ @?5,*Vn/12!8Jݡi餈IUZ*PnlOL԰ G&kN?lw]LznJ5㯤N =B=dv'MЁQevԇ 8qg[w ~N $wr,(gvh@{H3KY}'Ia=ij apēxOy:SQNuG})>si2& 3vGת0>T{*sB`38!Csvc3Mg?h +G3n(e{VVcFme^=KChr-9ZL,k!`[Up%wIENDB`ukui-biometric-auth/images/Iris/13.png0000664000175000017500000000655615167732630016521 0ustar fengfengPNG  IHDRbb 5IDATxk]Ughi)P0ÀFL5Jh DC$~"A4EI2551:|0(J|B1 B;gs=:͒viI󒖔ӼQ3p|ȬbZ(i(yk$ͭ3,va\-Et`4ȬN F̯YJc uBb2)ڡH[$5OꍩC;+(" 12B\0Ng[d1r6/I̎2!Q񺫵7( v6zk^VP.n(ccHcR/߼q#W\2-;_s9ON{v Qk.FYӖ \NYc7lR"'nUEԫ! mguqZ*w(lVT}4S! S¥]ÏYR66q=*O=[$QxSl >E 5GecH#A)S+C&Q;R~G.hA\+K@S:-7&ԋjM.rraoZ9SRK4Ū,jx%%R6&vVW6xkz]ʓ2ʺJTx@j#R6un7jf+힂Mo뭒WV+;e3R:5îċRe U V~_PzO{Jj `4q*լyV͜JƉ#PV;u@,3ZWRV]*)5`,>O=kTڱcjJڦlnroGL=U6|ZsM{Ֆ ;23a-_eKM%O{.qK(@e0dK/.^ vp0I7>Iepdk5f'j-g봥Pֻ'pwX; 񰯰|mR.5)Jb=w_H~R˸MS5B)_<.y_D.#g4p5GJ{֥| Gue=/sc-0Tch@Q)[ִR//ʣj>]J'(uf5Rr#l RMO7423&2;9 z*lVzv**&V6q5pm2J34f`)iM&%|9[\Wu%0MI",I%}NrC%$|I;%'9%fum7I0:^5dfa fF fB@[M;L@K@҅^' HMtK%]"is[Z;%k˥Z@80v٥' yOؽw<0v-OmV8ז'|}_$ɏ j i';pkl?^n!'A9~ v+s?pݖfg+$R]5ęǃ[^c8FjeH-R+X9 O$R+jPo/=][$GmPSvJ:ɜ}Y02pnWᲢ[#{?0JkG=ӼZ<>OF"02R\{wF<  ?V>F.S ^G6LE>38Tqg2a򱥄["qʚB^`R7G#έb9{q1p$Wɼ"~TS?<͸!qC[[IZEYmqøy5=Oyg>$yČ1 ~ U8+$:~ӗͳ 'nhw(Yax|݃w\unZo\v\g縴H%u..-( Tl)`!d;jzr1p '}BȎ$0Wph *¼֞}x{x-ye6Fwe²}AE|O#ӞwR(/j=(P`^j@*sM*#%e7hiT45f. r8bFJ0)3C$e?λ8 ^CVJTeFd/lFQO㉃^_ۤ+Jk: u (ǔD#%P.ŋ?8v(o d %Ӳ%>7=/b1{iǠlrQkوyY_AAuՌ:'eIENDB`ukui-biometric-auth/images/Iris/17.png0000664000175000017500000000640515167732630016516 0ustar fengfengPNG  IHDRbb IDATx]M]Itgf3 8 & At+tPЎ.w Pq r!2[_ "Й qzAQ|=:sQNխ$.V:[ <րH<$q1yHn\ҧ+#ҔNA*FBy1yH,vf]n܌~b4b8hE[\+; @f:)IA,8_fIڲ$;6O}R[0u4䱳I07&#hH a$`%CVM_W2w)$ :yQ7O6E7h7륂DŽKv=L3:ĥMI˫BC1&AbiQ!nEj[{\8.AU$>EqMaCgHbQ6CkCRnUBԶY4FK")*嘩wPCC碚etj/i=]!U2sC3t)PMK0%^=ty fBMzͺwˋl=)11|e5Ots:|vb# d;0 .߼;˫7u] ~wm,yV yM\DHC~c FW(sADڳ4>$̃\ }&.'ЬˠKJ$τms\UIU g65NԳ(F_+H4R各(Rk%+}ąя¥cCN$ ]?dw/G'Et#dlPV#JPCd$hJWJ}qWxgD)x UQ0"$Ai堂EƴbK}: Dc]q+ yokXE'eZ¤[<@vQlj٦N:Y~vVQlߣ6[%O_k;Gg)aNuB6mﬣi5[ph qj漺ܺSdA:N4 }M^4AʙK+<Ք _~c, *]H9]PRVֱ.ƕpmRlCVی%:Q[* י,_[C/Ua(Y.aP^ʫd LhkEQ20ok+钞_H$ku;qkxXҲ6q~003kMwTq`+\9_[zYYV5(wO;\g/}fY#|p\籄&#.p=ٚ#u_ԡ~ľ},Pȃ`vs^ESt6W/+sRv{;>gfp!U0j7&r({~n%K.32%LջM?_ PZQ )ZT^=wM?qi4pɎ.0~FFFAMܲ~r^݂1UԚXل jhwow$ L?jb;:Tuåe倡Oi(AĴE=ڝfo<RVjGU]aYڴwT!otuM]oV2÷r;l+5>M"Nf = d j]ZOa9@+]뷛G5o1,VU ]rݾ*rZ @fjo?bJ@kQdt!jN M,[f".(T"ƬA3n=-vn\W4.zIZ#$l[⩫lB,egƙfKHJ ,yHv5Ҝn?&hSVi4cOq߱%@{˿ܾ1):Ywz<kŮ^E碖]m]99n E)xf}Ңw4:[jxs@6ψn;EQ|§YPAt^VUb^$ $/$E܊>)em xZZ xMIN`COlgυkࡺ(GEQ<*Վ)Lq ε5C]4C4 o)0Y>IS{_Er(]/abh 0)㭪ϽHZA؀#vXhmf!>&0%Xj+0^.;oVV詳ÞCkn,G 3&[-ш#0rNU#lGNW|EkmSC`o"?#<Clj) ꀠ-S/OH? IQi@#"yFM-y +~#MVaA׹`m`\%|u8@֓d`m'Mma5O іͬe45Ίb hKxOʟsr.UVHMW-8a_WCCAeH),'g`2 w{"ZG| ~g ڒ6`h*|`wO|ā8='vd^|\4wRbcX >(*_Ľ!*0rG_cA~)0Tcy xWq?֔?:Lʙ[}xE~3<`#i KgPg#B \go#.'&A^[Ft,Bǀ>t t _e} ^ ߏU@ljq*eF ޖ]DN l]?}g0gT XC8c&ċa ]f'h7dljʀ1,bi*y{cb!B:FbAh)2&B #l෪}+r\5o{X*;~݇.榬uh^ݟT{;߭F;yrh iIENDB`ukui-biometric-auth/images/Iris/11.png0000664000175000017500000000675515167732630016520 0ustar fengfengPNG  IHDRbb IDATxMG;>p;!PB\N!wbA. `8 րC">u%fױ>vuuLLOzRgz^Wk`@DȂ, X,AD&EdVD$C'ƬLB*|2Y@PD9L RJ!"3ELaf"VyKADz,2+y0GӇX%fFY]B in w%"SN0BBLe%)PYz-K"2=hM@C:sc$$av`  #az&CDm`OJ_Whf;n0MI2s]"Dn?є$vs})` cIUBnW7[)՗7\ǝsUn`ve|ގe{VA8:~fꎐM| ^uUݕ-:jsI}5Ҭ[5s2y}E$.HSP/a=ۦDrZJtuDNJh%h$#mb|ŚzlwX:' >-]gUBIz#O#O1#|e}K 17uAY !!a&b@*5Ҵ|%z#UIͪͿy}O۵I.YͰP#Pʴ%Cdܓ$oX޼qW\ǃta!Ǟ!#d>p=iHY;Y2 *ҤV [2%i(m-tTTom`rJ”p)WFf~ Z6Wq[?Ɏ O"s!$)I2c*Ri HhkCzj(Ǩd$g[W*:#9G'.ޥ|b) dțjGÒ.r|a'^c娀fI- +ӓWʢx_ H$'6N\ҝW),lg͐.ڡ2v5$D$kjM]T*:&#*{ tx*yIk`GNґGe! #Y$Qkx X~Y=ڡw%<`5;};I]tL5 vyGeJ IG~B2 '-(i5W;2 ^GE&d}R%NSWuiqpb)uF3Eu/UG(RK(}=ogs_Y6/Б6iľI[C|ƾqnDd؆Lȸ"0YBG;8_%C}hyWnցWGB"Ύ ͤNɓ{XDFMv >VpjevѠ#m7xU#y"8mؗYM=,"{|¿`9go롬n Bb%Ϸyvf1ιN HOen8.4J:%CD{=jWd< iźS]S kA.k5`9jB$E0" EOXx36dzh/.(D$V*:>:MBp;(І秂dXoAC?sZ< ni_ YH%d^t>ιGA%ދȈv|νǣpx-m&y? i*p򽇴 &jg?&!v|; F H^?~]vbd<@BgO K{6DxxRƃs)N6Fcϑo 1 _ARXqE#wE4N["l4/BR< k5ϡ,d,YK}=@TCm?<Mw!A#v~$&e -;;Ⱥ-E'QO YA?i7ᆮFvh?6t\G$LUܪF`l~РcP71'-ۈ{bǭһL𸊺p V kN0]&|r̳v+2]IZs7YAUkfL}j7ٽ9>hV`e)+O+vXе:HϷȳWРyb7_[ ț 5.w~ ov*{ hv6ZHAu*VDW(!;Ё2pjK1Gybe/VK: r}(] N;>Vpv"wqɎ+tAi|aOAetk-)O%yI{%c?hz/i(~n. < Gi vÿ,e z .#+hQ;Qfaw5 Es3~tOp߾tETw$ymB뵕=(kH½~˟:Д:nOg!@KOSCIR=#DHugD}B aׂg*LCQ0Ϛ $mS%cV7"+(a =69ٯjHzMkF@膚CmE1M1!`I6{T(3!7b׆ iY ߟu}dkʲc"?ImY!_ XC[Z@te6 9IENDB`ukui-biometric-auth/images/Iris/15.png0000664000175000017500000000661715167732630016521 0ustar fengfengPNG  IHDRbb VIDATx][Izf2ݸquAʼnD'DeN""슂ETf ,^,+>""8Y Gm&|Sӧ/L@=]U;uΩSii - $Ĉ#?$g$^7ޒYѫ<,|lYꓷNn853c7(",n̒džH'{A/z w"똎 dCώy*$c v4$#h[S5ӍH.8)g0$d͂"ciOF4鑌<fE5lx=fQG@"QSL17:*"M1 m=B *E'o:)!Ii([DT83Io`}{Dg,\I䑉2H4EN6MC,=6%u-OZJ_H6knHQIc ҀnʱcAL *U&@*lnV.32IY3i l*!Ӆf vzͶ |kcldz+fo$r=xcyb>'3Aaб!:շQg'XZc:Ob HiyWoߝLG.]O_{ ̧Ռ UC>9ꉩ!m %.@A){Ag.>$lM^ S,P9Fn/Yc"yuӠ$u`I3?i>cy48ޝ1é`D=$DG_F͌X `ScY[P:fqL̯ 'fwItD:^xӈ))| U?Btdֆ(W: ~VRu78#|wNT2쀇PLu.HA9mĻV6 #DwdXj3ZBĬM+#άA T֒*)ìZ5L.<*ZTg:IaYQ ^zRWuoe3+Gg.aⅩ05Z{)wag W[pfh qլyyu=񂴝h Ք f= ƨ>4:z2VRTߘ5حm]E<]zm RԨ/%␢ufEwҩ2p)=p)WCzyF<$I2a iK3Jǽg%=֧fԁ'Tǻ x7X_[&fWⓠ(U3HgYw7 Q|s[BzsBg9GLWѡ_ԡuĚ/t,L}v=#b#0 4VUeT8Z`.fbupl接2>gfMjFNO EǾ]Q ƒ-` Y@[*4lG3@Z1ENr]R5K%;B;3m:30je]4nM26Vm6F@"ڠi%*0PL6__JvPm:m*xa{1`I#!ݗhGm濟،-ۘ`6h&u0wGklrXqg~6;q F3;e;ꚘUQoe&7fR΃QqG~|rvƧ cz ̆=gTWE[S?e* ]ߟ.UI&ܘ=()LgeA`RMtؼ75?[ۏ,0xR7h%9GyI>O[*A){@%YmLCD pTSrMhKt'HmU3Ÿ?' ຺Gݾ hԞ 쌨%IK]kp z2! A5@"dN^Syg$068b$'BJUlÀ$g o<(=7Xp' OHג$G8U(QĢTp:R͜|N>e+~` UTa7-wXpI7O  꼍HPD%SmWeTԹ$IhtA9AN"VP#~/~ip^)G~tm>$V0p3*v:DE)قǟoV* X *-/p;t*_x/fx} <1p4w+_1,gР̨7I*+ oT7V Ր9{ԽC(U[}'m@XP(RW/1/QgOS],g^G:E 虐|u=R@u&8c1tuYWk ڵB!}oqoO䉘y $q+pRe@).b@϶xǶiG3$(h |4j{.e~j]ĦohKC9OiS@2Pv5ټu|֞'{NYT`So5g=󲸧?Oݧ}ڧ)j}\F9KIENDB`ukui-biometric-auth/images/Iris/18.png0000664000175000017500000000447615167732630016525 0ustar fengfengPNG  IHDRbb IDATxu6FA7 w@`݁*(8NT@Jt*XO >VwI6 0 fXwlx+՚,`+vk3;dߜ?V*q 0d&mE<\ĉ<8{*Qnvv)-9k ~ %c15s/CvMS/8=mJi9k4']_녨'CB^A5 1PFȊpL&2:\/_/!h mׅ["˘)t8fjo ;+3ʴ7碦œW ÂDUDOJ]UU_yQJ=+^gQB xVJ}RJ}DoE:-OfUk71I@&ƎMI>GwIb DyhWu7L]LؑV+otuo)PgHB2TP˕CO{/L=/t?7Y(tFH"7& {r,M|.@Z/t{,UXMIW!2I]]^zzؔV z՜j@څ5Cjc1` v*[])w7_gVgB촧m+cr\.{Hqzb ʑM◦3f388]^Qolw Iq-n8f̀wukbWq,;>roQ"I>dO;~Ox:b H1ޙs0kHDޡ(2q9jJiGxdE;&!Bn۹: =xA)%`l'#VH>IĆR8y6˖ sc6&]<%<*|UVuY*R~CVLf_y2?`iU8a{\:sؓhA S&\6 xFg &ߍyH> ]ό\&H\ɔ;s ad& I(Wk" rA&3ν1O贑vJ-ԮD"jl vZ`Ƶyݙvm;\r. g|EtLI%?;*U[Be.oRzy'~RJ}WJgUU0mAG)!!~-_'œTk:01AMF{!u.PI !4@Sh(1 .ncr0w,cu[HŒɃ /8LLf=)A6iwSi ŖI ah)罒]c;.IK ffD3r33&9e 26ޙX I(MxAI|ojtR*)v/&;}6Rya^ 3It%~Ls??q}7f vYo]j~MvqX⎿Qggѹˌ V"6Qordž}\njg.&M -d Ro61LwV?HILn67AIA-V?Ј,(flT , r̵!"Ol/jz;DLj$@?[֙2DL+D:#St>^+{p@4u 3Dέ)[WoP룩]UCSb0Qo0;3]{H7=HhMK.i+7NRh5'̴n&)F+)}k}?㢻|ںG7КV&v mΥն[фWᄾ-sPv*j7AJsI@{%YnjcUU.H/o^Uo_Y0t1+2Im26 a ґ$y LhYXt6|y;1&0 2̻&Dc,iބz.ճo v1/, ;\BJq iɝ]nr! 0Pi-C@/b`K i]<3l!6-2.x6,~Ҩyu pP{Xd۹r|ʴ\jnwWF p ZgHii3Sg8o>ks3dg_ξ|kZ{."r@DEdnr̨wȖA7.9$"sǾ㐈<-}Q*"ExkETaFʛEo}k@j%wȿvbQZk!3k]5'tGu ZRD`mq""E*KeNDnLUi!AyA bI840AU %aLB3uqg?Kb(3} o 7MIHDȘq "ua mkFEĭMʦR sBVw˨Qڙ8g?sιsU}aݽ9TuID=<7&#p^F )CpPJB 9l}9O#M6ׇdU%h Xm%x'%b9N1 \{8QPɡ֖."}f]J5+O`AU$cI$t EOSιǪꬒ9K""2WdXQMJL2z`s;_3S,N@ o};[RdUR"4恩:&p#/){E`QMõ'g?/KYV0r}L*"nDžߔSD=o[x?1^.s$ݾO E@=L Ee!ι8DĤ.>F <ChOkF qr|]ddiY۹%d[ƻ.PR.܋1[qʶa= ]_~hmfUEDX2>x/<c͏{es|9Xz)JbE0NVفĄ\|oGgq#l%"86s!-1+ǝs-/bm%V|)G-7-EBFNT:`-||1>}v+yO0NE"e]T1 a|/;Y#)s@BY[FFN\Hfq`C|F5O:e+RFrYKA!ڠƂh?|oZW>xL) EmO*Κl㭈_L:xI5`g EL2y2,BDv=7Zo)5vip*H8>8||_"+sQN0~(w)ue:aLU`ɀuCe6?wDz2nަ=y,aZN=6oG&#yW0o@b֛]6.퓋t{ߤnכŖH,7]m!4p7>ϲvFS}SXѥОSvލAgqb;]`w/k]TIE-=6 |U'w{x0]q,+Dh,(j uzx*O[?󊞓*OKt܅=fo+/ƺ+*dV]Z ǖ,eAw3| 8^p(|*=="SvıA#iƮǻszj UUYjݖ.2mi/8ި8^kwΝ);7ٓtmUr%<˖r2٪vCN:q?5(9il~oѰ}~#D֘&Gm ιDd_>:O@q]Nshj""#Xz~ .`5uadͤI 7$Z쪗6.yܙΒU:]%QNHԞ[Bm/$5H% kŢ{>%,C]i04zLFȿt s05,0drKg%聄Y+GC8j5%jwjZ/"AU-a/j N?50iDky?]8ywF v,ݹuj3{knFZ ICdwz;e8phѐJIJM3u۫N^3'jvl%֠ :*[t )dنbr m)B%ԵPVjL &SGS4Fɰė>3E̝Ap(JruGTgǂkvF%G89mlJ|0sl[Zr Ȩ|'6Sf֯ܝ{,% <T-* q/ Z]GТLƾTk\!9hY~UY@>No;{W˨r]M>3j`.=,t0> RYx]O4E>h4L?9&"Y"7_=. t5%èl'=*^|ZjSdo~O',^-|.~PDTM;O(xcǷl^Rc'=Y[+?/(;R-SUQUvr#E %!v72U7y{4[z/~沮[] ZOcAWnHf,LqbAFd $n%ѥLxc{ZL] ,nb*"'!(;hgzm){d_ge Vt+&Lrb]i@j|bc큞-OD)ӄvQ%oö+lw Ǒ%F(C3}m0G8u&'_שۻ[l"e x:~ f2.M!ɴ>^oo1 nt$:=wHmT:AO;7$UyQ/!!aF5bt|ij o. dbF1DG7Pa(Pg g! 'L:Fd2#X5xW jFs֤u( D9YY~~f Q+ppMTMΉ!r~E+b`)䓋[%@ L X}@|m^\@SEeoIENDB`ukui-biometric-auth/images/Iris/08.png0000664000175000017500000000726215167732630016520 0ustar fengfengPNG  IHDRbbyIDATxoG?븩I))I RR( įDxAȩH  %Bwڇ &UQ#MihH+=<ٹNݝ=39?.\u\@D"27`9fT#"u "KDDdN?@ybLȮAshG>Z1^("[US B RBDX*o)Ȥ߀B%G=Jb5df]+9.%djǠe*D ֗DNGeND&-S/^:mzȆӂ"3X&$]$~Gy]CɘfDhxC@;h̔dk!2S$KM9vVY|v Q¶W7 ƂD{ιv*`P9/>볺gyS}@-`7p9N ;I5pR{T:i-kfU"Cj?j5I=6Ҕ.f̹QEd&Z)Yړ0Lj`rRJf:ŏu[s҇[wn,PWS/m^:-R=%d7R= S§ HL!*Rě9B@H8ؔH@*6ҤϻZݥqF" g~Ri5sfwıʩc y̑ƎMMxJB{y<:83p$۳!?7\b$"&'YCw/Cκ1q]O0'5+|ɲDdTD6Șluo6빛4ؤl&4q+:LAAݜ'[O~83a/:]Fv^5b jWι?$vdD9-F=|ߘdp&!48 ("!,> x9'$ >eqOtnɫfA#nŧ' "FЖ ܬ;W{ >ZƯO:{%^r}! f8|UwO7t[DOq [YZYRWOjw52 )#N'9׎WZȻRDh~$( ߐ CIh[V x$XVwrG_ˊsnU? h",zpw T"K2!c| |obʒ^Ho;OߝkG[AS Ϙb^ƷD1cZɛ=w(GBX&2}5_v:Hˈ) u yd'%6#Ո@~@PyXD}@!]1#p'OB?z2'(&E, CȈA?~'㤒 oDDQLY"m{l`7#|(tD: 1 0kdRd4Q)R"_$OD)%~c2^[eD#zX7gi$6\L~4piٔXbbM]ZV?H6\&k|7]G'!5"8ᐒz512;~biJXo; ?LS3,nS92x2> gES6`;i ᖵٱCٷTAcW}3o;㔓fќs ]v,\I9J:HPmLmע퀠M@KX |oQ!;-x3RR)}#aq iN:f.l1A"& IHVRuiˤk:`ȁQDdmoٶE`8&1R6ۦ*R|]R){N0xlvp|CD>KctT1iV|үU9[7ɲY_e&k~=ήɝ#"Lُ9كLjɛGGLYrlYaj4jU%JлGCP\ŏioZv`Ff=u\/<{zܹ[zsb4|n92KR7sWi^bıfI5 ~tfB/@ńY $ AJNKTxkeȈBƸh1U2b3Uv5oλ9e/s ^ܶ6h,ޔ(ZHe^*1FȰ*B#e~vS"lY8_R9%FS;KNzͳTXvr9iG;wp9lw_|.M!F"?`ձשo%3)Ozv|K1M/&mMV)3WMNݼPƯL{ڭc1MXU6ܵ+7T%ْ!kut@lgɆ&"YigyØ %ιO*w7d4?K>%C;Tq.4q>2 ֠r:xbVÇk֑&UTC;UrDd6H~EǷ0q*]v}pc&suHF$W_Ȏ JvЩ!mO:P׉PM~ %!jӘ{H+|+IfKv;zq-krv2yG8r!S|8{GB쥊5sFBD2mi2uL^'AßМZ,!m OH<BڗMm#̃yM¯(`9Xe h$Ȉ0OӇp4nI (ݰmFK>ńט+5|c9yTVƢ(Mf,CD(=j8YӇS3 _v*MeH GI}zC݂f#L^c=* tݤ#[* ${V^h/Ȓea:ko* Q3zy00#x{:CɿﯿvA}ij o.GBX29Y~iF T>B/=5 Ŀ!9a{m<F"@v< kT}O.C fhf U^csޣB!}}0"~3T'mC"3j;" FBE=c gee ~aqQIENDB`ukui-biometric-auth/images/Iris/09.png0000664000175000017500000000716315167732630016521 0ustar fengfengPNG  IHDRbb:IDATx]Mo~%[j5rq,nR_vE r9h.Zq=*r)P9EzprKvn8Rå $Q~zw4grIzr3~p L&X9'y|TS$I6ąb ;W<.r܈23HJɅq0 .@rNս #"X%m'ə='t!:-S*X8'E9ThKܠe'"ՋP7;+Hs˃D80AUUO|Ip yAUVTSKtc Ndd #$IYuL{!r8+ rߢ/U3H֤FH!y8N|$ɗz %)!)8cRAnPg/ ȨnjM--sFutq$FH&y% ?IYgH>&u<"uN*=Ac$PvOLo3WҾͣ/-Ƙws q9E:r}Eq/< R+;pާi][j`3L ݈Бy^!<> ۰ԧ55Ψo!,;(jR_pXZ$wl1Ϫ*YD0mDBCNKDHB7dЕNKD9NFѮpۅdIa ?Nm<JHНuG}n4Ϩfs א4n`;\N$Mi&]U`vAUkrxvx4?,(lЬ5X8"a$qUGz%##s&8"c^u[ P kDCB!I2dvR",#hΎKKjj2sM\j Y},ɤUƎ65"=#>C:fk7g# D%Ϯ-51 a{x0A &K-*9_ppc ;cx5 i leP[D`.;tuNgbgO¯Uv4#5.;ߏiЈfCO :]lo4^Odms]GK'oS:*g;R;GIr6S [Vjv}siy#=#Ϋ:D c̽LZ3ʚa(l>L}!1cU&9Y@kF!1f  Fz I  %mXm,eMw" λH*@I'r-Da ?@M:>S:T2D\#&[N(je}"HLa2r=2So!$]m 6#'I+cÎ{sfY*hy 8Ltvvz RsSU;EbK!"ҐJ%}G7`pSe#a)9|/O\^mca"}X?4T9 buߐ cۖ{1KX)<?r 6d tSkG*b@캫h'aJG=ӪeǽdqKY XoB&a 2`gk+R1;S@,.kƘ_]#d 1ϕ%e@ĈƏ>O=CJ[/N ו+(ݥ廧a|ch؄}­sKd,|ʣ֣d65)0躅X,k1aov҆UX!W>gq a~yŬ=  K _w_|пJ(VXŻX 9|_/ij.Uc !4\!ld2(tl\Wq ~j!Ο$Ke)i;/R6c*UxirGi%$k!=5G)2I깮+wщ}w%i|2 uBѰEaR.ě0_QK;U+H>q^Muw^HtQ5C]_(VjLe&"*ZeSWY~ެk2*(qzGc!zݕ,ʔ T`Gk*{ dJjv-y4.%iBҤ3I.#2~@d(uH|.X뚴1kII[%mS>d#^I{%= je$%MEzd,Bsq (Úq80fep/~,𓚲$%56pηےUཤN/-9c q% Z*|XhQNc~W{;$$DW(!Icιu 52N:q9a*N?=2?P0Y$I`Y p)ι猌sx=<ђoss6I-|L݉ ne$܊҄C*✋[ιg%3ق^Suj1 |sJ=uNI(M@Ċ'"Bb ZDkW,S:E"bˈIE85cE1a@x+ c\wߑDJ0Ipo_kIL\pO)9Cڱgq&NJ&.i8B~ @F*Yz,yDFx0GFBBEDz݁@-&Ϥ}!uvh]kHs>L5<U 'aBܱ 02ވ) עl/n5vy5$n@Bybm|ɓ6cIs/ê0=qBkrIS9tr&Y'/\ŏڷ-"p<[G"|#ăC~o@ƯH}ڒ' (QE2ny GMYX[Jy[@= O'*>_ZFWkyvmcwsmz޿o/¾IZ&K׀ڳPl֩;~mS&u2>,%¹ K{S}LQ>+7-uXgo#pqDRqt4|/+|FC-x*zn$]: ӘaǪW{=xwr߱ ESdQZ4+2  I#1{tY1+o7po"YcdVϴ͸m@~ y;K7ay,irTzwCV3k岉. 2fI^;Vsz|:V^IEu=5Q)X~x9wNN`9"ku[/j*s#av Yuun{ oU R.uq6o r-ה6n}'*j)$nKJ&虈) GrsR)#^b$W+U:h(Vګq%aT02eLf8 XD@bnoj%S/ 8ff׼$\>J~ zLNYH{8蜫$_BrM{Jn .9>WLaS6d]Qq v]Ϟz& ,RND MF#d/-׫9%zӖM져oXW%gsO=ױ5NsmJ8˻\cĘk<4o,\R@}_ibd%[7TU#ilo,:QGQ:.BDp2j md ᧚ : ^NUY]'Lk>ѢALx͹-:,/-ZӃ]zۺY~Q!]N@# ^-y b& tF7 41(K!b2># *P6;Ta70 w 4jۦ*cf7+haEoc}4hpZ2sʇxƌ#G@voPUYڇ}֠,f/ .mQφ,ˑMU ?شn!!w3zIENDB`ukui-biometric-auth/images/Iris/14.png0000664000175000017500000000663215167732630016515 0ustar fengfengPNG  IHDRbb aIDATx[_G?gw{IIx)niU Ap+7"J}pSV|}Gl|QBZ*VEAof7ׇ33gn&\3s~3m~3{.%D3@V$42}aI{HҢB:0E~bIZ?c'QOXJkXO4M:%I;EF6V"I::S:dpCl'zDپJҎcY@|6O)3鑴 $-OqRz OB.8-(#L"Ej`X3$$_<܋g,iFdf7YRQEfj<єX^p@]ge]ڔ!|gA*ҬB'CY}-M}w^oSNY=>QF=$5˲ilue+Q.BkC'l[˓6/ m[f(k;H=an5J]7(ID54c ,н&˪错,䂎@X{O;f(KJA% ꚊWn5ϮR{#%G5h+ekɇJސejzdLZ bb* &:֓$T AZV#'տnE v8 pCܑMm%Jyu7sEl G [K]]!FڧRxuZ9Z$TM [Bs_ gmbTK0Gbul1]Ry-Kϫ4y@f*Z ) *NEk FKuocͨ4hә1QkQ&fٯ?t^݆ZXI 5y[D=?T1FBMvR,f+^uVUUO4+U%z-*zպ)З*ԊVl[+GkpsX%D7v` `*[տd%-H%i$]n+Fe.ּ7HJo4N(&1ɳI?(זukX4I>ϝ3 { 8!O̲?Jl6hLc ,3o`(tBqʽx3`@Hs.[+,˶~V{}>VV@Xb]#Ymw=|ז9 !탑:9P{Tr |y9[]> sY}p(@8qSf=-`ҝOWWJ+ \|xm{;˲V4;@OmiA̠?O-ɵ)q?w?~Gˁ}2[Y5P I .@pW9g`a`~"#Ge (瀫1Z~*ޟ{۲[쎭,V:k];<xȖq`EUĹ>X-rl-`!O9#r.)]|\c4 fTEVP ()[˜տIwE[2c,nu$I?|0nrkw|Y^(k AkoxWwMߓv Àpq),N[ve8P7cWG&zHU0|*ap=. %4 ܗeSc #|>E?)P|Uvf!aLb$v`0)0q b{xY{cX}b06O_eIrT廯}L6 Gi.c(61퉝cfbS? /iL\ ݿc<6,̭Mo1t!>hּ+0$)u >kI~ ًe?ߦ*@¤h fjwtă]X=I 5Wzl>O:9mgc6ǿ8;2esyL 1n t>&wr M o=Qw;>HԤ0]'fIDGC o„M~>Hх!bM(.D_ I p.z"f.4q߄ѝ+W&_1ǯ03л0yxΐ:SV֖DlR[CfͱIKq&,?O=QVOla}Aj wN;q 3߫{v=;{?,s0:LvV'~v"%Η1s}x,QoǙ{ʞ];euc~]}tRǯ{%]ф/a2Ě~kFѺu?nip;eɌdrL ?λ>V/Տv@*nxϦ*b@q(҂RvI QSnD*~ukui-biometric-auth/images/huawei/0000775000175000017500000000000015167732644016135 5ustar fengfengukui-biometric-auth/images/huawei/11.svg0000664000175000017500000001260215167732630017073 0ustar fengfengukui-biometric-auth/images/huawei/none_machine.svg0000664000175000017500000000242015167732630021272 0ustar fengfengukui-biometric-auth/images/huawei/07.svg0000664000175000017500000001260215167732630017100 0ustar fengfengukui-biometric-auth/images/huawei/Voiceprint_recognition.svg0000664000175000017500000000175015167732630023376 0ustar fengfengukui-biometric-auth/images/huawei/Digital_vein.svg0000664000175000017500000000251315167732630021250 0ustar fengfengukui-biometric-auth/images/huawei/12.svg0000664000175000017500000001260215167732630017074 0ustar fengfengukui-biometric-auth/images/huawei/01.svg0000664000175000017500000001260215167732630017072 0ustar fengfengukui-biometric-auth/images/huawei/13.svg0000664000175000017500000001260215167732630017075 0ustar fengfengukui-biometric-auth/images/huawei/04.svg0000664000175000017500000001260215167732630017075 0ustar fengfengukui-biometric-auth/images/huawei/Face_recognition.svg0000664000175000017500000000144315167732630022111 0ustar fengfengukui-biometric-auth/images/huawei/03.svg0000664000175000017500000001260215167732630017074 0ustar fengfengukui-biometric-auth/images/huawei/06.svg0000664000175000017500000001260215167732630017077 0ustar fengfengukui-biometric-auth/images/huawei/02.svg0000664000175000017500000001260215167732630017073 0ustar fengfengukui-biometric-auth/images/huawei/08.svg0000664000175000017500000001260215167732630017101 0ustar fengfengukui-biometric-auth/images/huawei/14.svg0000664000175000017500000001260215167732630017076 0ustar fengfengukui-biometric-auth/images/huawei/05.svg0000664000175000017500000001260215167732630017076 0ustar fengfengukui-biometric-auth/images/huawei/Biotechnology.svg0000664000175000017500000000600415167732630021456 0ustar fengfengukui-biometric-auth/images/huawei/Iris_Recognition.svg0000664000175000017500000000157115167732630022123 0ustar fengfengukui-biometric-auth/images/huawei/fingerprint.svg0000664000175000017500000000413415167732630021202 0ustar fengfengukui-biometric-auth/images/huawei/09.svg0000664000175000017500000001260215167732630017102 0ustar fengfengukui-biometric-auth/images/huawei/00.svg0000664000175000017500000001170215167732630017071 0ustar fengfengukui-biometric-auth/images/huawei/10.svg0000664000175000017500000001260215167732630017072 0ustar fengfengukui-biometric-auth/images/FingerPrint/0000775000175000017500000000000015167732630017075 5ustar fengfengukui-biometric-auth/images/FingerPrint/16.png0000664000175000017500000000653215167732630020037 0ustar fengfengPNG  IHDRbb !IDATx[$W53;$;KqD-QL#]AaATQ&B7A"Dmi0n 0Ht ;7\>w>s=8ꩪS.V"r@DNȒXdBD+*pB!V#!䒈mBDUKF'Ic u@ 6n "dolܡ+ "TDD IFxO5]P_3I\g}#B\|}hi~PSr2ph'I@*YnB{U'eC_F|ZqM!I[=^-ӢMപ3i#p҈)Raj!"iKzt$E(${HbQjĖE c^|E߈gOSWCȩЉӗe:fPbDC4e l];uD 44lؘ#fcX%{InC?mwAGCcea4BD%IFV>jcU ø^wVǯǧ\Os%.8єojzKC4'^Fl_5(C= !KjBa+F"xm w^N=<.ڏ[eg$ch=`ue"r77{xܦ[ NٛeZt#AG.ƮgP]#MhGZ}T<I,SIsG¼&,ֶqԑ~l޿h.ŊS} [ 4^aBzvi hCK˞2/{bEם,0ibP2r_@[CFqDǐX aG@\߈ڏRod l.96ˤ}V!xGFUa` 7To7&Hosv~^PdwĀ[ACؼd#M#oHw@TT RaaXBҝ1joR_xYF2a`j g}2nYBݓvV`^Sic 309sl t)پ @$g"R ifHLs#_P< [*M#)T)$J÷x`l^/ gg:VT`P"\Dm0U qi#oHjr_roV E%MF>CA:4o\d-B h ]R 蟙yJN" _\\mpߵ#̹ Y wJȽ YEw.y1y 4-ryqMVVeA[xP))'|?*::/vܗP~D[ך&Dݧy;~@mR34Eۅ% DZN\oѽԈ}#-eiؠ"4lx_䒖킢hX`>qRp<%{';C!BՎ#!8"s9-OPUe.ɇtH ǻ M7orkuFN%ϛ"KQAc᫅lr9 je뱫svvmI:뗻"Dϫ]#::dIDdRDDdLu"s="7翧LkSZfϘ#e|Mt =J* M׿VN/7bҦlz]""Sf$qu ;jxKo&In 5Wl'FefM{"M%hX|[GDxx w_8L?i&;@gyK3zIׁ4"Dd')`rcd )|g)&z) k &{p!%MAa$Ho1e܊WY$kImB!!1rȘ9g#F'{p{r$l1e|6L&|4cYM}A[xl5Ò5ླྀZ\& .!%In㢹/44qMm &"$jE\ |Fq%%0_? %%IIQ-_s.kzNlxBp{Tvցx"MqI}?W3BYo|&ax5o7BmɓuU_-PI)Kׄs#IMVM?jʰ$z[wmw?#be|G9K|k>\8\mɸ~/UU/8 <<3}1'IymzZ;$dt/"KBb_qḟ qG/:z$lnk 眭y)ylۿe]k Pl}t;}yPEyx8v MMo=8 پCZǼi ΓorbʯF~[͈vE@*A{2u]8"#4tސMMs8B79 8lEl[*Z{T Po2.acI~ f\_8b.qi\^ͯ3gcO?co/I@_:a/v6Mڈ5ZϳJ'JDЗ/k~I/M=S֦>o2/[Lwc艌Dq>Dn~ -$?&sΓe̚ڞ=8oPzӔk6UDK.HXEW 94pc$?D\ p!IMÅ3 FIƈ Հ7f5I~.IKն:Ƃ%@Z,(c7d1e<=J1D,n^x&w121D( wLKI82qڵg^C h DK鶦Al0j2?c?%S>$8R"SqE٩_h_4^/ë]6 ; ]ͻ>!ݻ߱?u:IENDB`ukui-biometric-auth/images/FingerPrint/03.png0000664000175000017500000000647015167732630020034 0ustar fengfengPNG  IHDRbb IDATx]Qn}ťIZL(Р!AH |˧  \ d>r l@` LBƔYeKU>SYEz{vg{uWWWW *#,ѓ{r5ϗI鉤oI5?1/=1}J5C0='+`OLϤ)dӄ> "A_F±9WOs%!ˍ|ND3|v/ wE+(m!Rz3g!T1Mjߏ%?6mwQhџH|(%/}UJeX|e|]2,RH81mo's"dye8v$XHr$_SBGSUE5 6,K c?f /Yu?*H $ΫzcHKQEBHTMYk{ˮRS"x `!%L+޹VTklO ~&=H!xY:[5Ɠ/C Vg=l 4 \Pf@\Iϲ^efJf^JŞP%ɟA ~%C=<4|!#ɟ F1:=&p͇"llSgxzqAq.J~Us{=~>rRz,ОzߚhBhG&?GC?2 ~h;0l*Te1,5~!)_+FagV&et gq G24!|P622yXN݃U 3-Py82.>h<+䟋585YvI}.CV< soz$[MNE#$ >bQHS SYE=-y7:(q*aa `[YC1y n4:): f6P9Xx:=pإV"kaz6|% an֮7}G][Dٸ7NW?s uqӤf CHD^Lb e+ CHgD0 ,{6PB~hD swL=,!8?ӫPd%"{ND{9CTpNn +2\CizQڂn:fބ#pcǓdd!#aGB!yD?vmFpxj,"b%aY(Tbb1(,|El0ȱtB= ?̈&a3_DA{jLFaݾo@@Dt$Į1ŶP*2u#\=gB?2Fp|'>fILx3{%Cl\#D-K["zFDD4F!f.qC.|.jhQ'-A#"z(7):f ,70jr(02TWBZf,A,hTtWªCaTŤ[#ZDXHj wcz*m rF33mN<5޷g1ojo c6%*D3~@{T!sB\F7tMyFbc2Afxf!BԒ 01親r ]mIHTwZfE'Dպ Ž>u9F`Y8ɷޡ߹J@BqTDZE6a \i'M& ynjKWt^&d_\tfZ6T\]Lho|n \k[Y:ח"~1Q < f& ft&Pٔ)YjB1j;w=Vz5}z:m5Y wՖ %aV/,r&:@w)ظ6ɗ/]MGu |P !r}Žs)B:{NHlStqhJazB!N`L76ɖ}I/Hٱ0Duno rkD3o5$3 :GbhB-C^dAgZgSu6XSmkpnj_1BS )IY3 6`+Q1.\a'+,GY?K=7$̬Gp3ɝ7Nzn+&r+ODE toV>2 Dv2Dukfz2Eu,,ƋWJWOXBpj񋺚b0Hxʳ"_3?"CB-xOJu|z&d*ɟ9?̺N-2|S]ԌXf\o8a^YVS Uץw Qj1C!⑀:!S?~^x+|@'rkeqķZ!V1S2g,43/!,BZ}@EN\bWyWOty CvwUzgq[҇Kg坆1QOw:;fc~U?g>|p{y/P~Mo1W nc_0 3߲kHT5IENDB`ukui-biometric-auth/images/FingerPrint/07.png0000664000175000017500000000711515167732630020035 0ustar fengfengPNG  IHDRbbIDATx]heW{rD3M:)mV[[nj(/UAAQ>2EPZR&2d&5;M&^+wߝ}>9v>swks.Ei9[Y,r@!"=ܟU*q?2v*tp򬈜 ["r\e{6dm=0PB Cw`|S3{lM7ADP/9ka&V ) ؙwνZe{#B||$pBz 92FVs Ḇ毪ĢPthjG4Atzy(ӣk I{2q9xmiĔ)A!>rZD&zYJ#XCؓ]D ~U߈oDbӎډ$>5]=@u2$jEDM?لxYvGv@'"8`efAmιF#Eɿq 0Sd@9"v} >r9ra@^nn g݄dkE`W v|ڳ TnDm[|2:$#KZ#6 ?uL6|IIDc*!BMгʐ +)s"nMSI*"n $ x<TnKxuN}NwÏK7eH|ι`eLF(p//ׁrfН8\~'&|e Gń . DDx?Ԍ~k+N;(0>`R%{:҄4c !}qI |LPv<3BƂǿ+LoqCty)ŚeߵmLDF8a)Rom8?gTadUDFMkz%#DB?p8~e /*ִBgi>J3G3x3_em$iX:dd%P32Dd9Ԝo!dk=x9ƏWŢ0-a4|Zİz>Xr*8x'uhv|x0e 'io #qН?2pψpfw+/j7͎(_j'8׆*~{yc?菏 z^ [<iѓmcT WU@X|ȣ*?)!&mma@~;ؿF7qd)J#ܜ^m *A tw; z;Ӻ%:5h,[;vq|&sY1szm04B 2Nmιk=mKc$@SJ1ݿ0&LuxXwέU`h K/Ԫ x{<9o;)HksnGmsM1&!c(s[rR~|ah~hy:,DAR{U^kr_~/jmd{1W*Y3@{(ӏ*XYpܪS"2[c4>-7l9l ιP")Zg:*'BDf9.5Ra혈-KYVj&0u&UYA)`+ߘmT"sωQsj??Q)*%B<Au+9Kڦ "\¶$휻NtT&,s~HǛچ[n`ADv眻)"x<Ѿɜg+C>}`0Ԝtoιsιk^JvԆB|mpeD9i=̺9s=kY}_&S'V@OR#LE 8B;AXu*3I:H?koKJ" k:f&I3y᧙k,{jL0Z$EB=s4bKˉkFY0뭙P!e}աi}Ú& E,B GO Ԗ}̀ 9e!ea"gӴ1&ija<c=KD<@e#TB͒ r#qΜx^ztp SԈ-~7nZE#Du;}r(6cu=f$cmRݐPT4^F@D,UfOBϭk蘸"TFDƢ<$ wo"yH. 6=mr%'Ik_X"gN&)LjY1(F4sxsԢcRGLMig_kFPA'-Ɠ*q Yi9-3MapOϾւ1˒x^'45_tY`DAQSM0$Wiv-#Eio 6/J 979fv}M&{ h)gmS-hz>bRKdJ|V"̈Zk"B%29 W՚G'jGё9ݢQҥEyu]B| Ɲu5J.y{E[Gx!cԮ`;&t_/zQeyhiiNKdf42{"l:~pc;xbW̮f1"zE5ϰ0MJ@DD9ZGm_321D_ 7[łğ121D( ̬XgR]9#KDDBllu+BQ2MPI1O++Ose40 KIW܊l#Ԑ.(mD U^HAszDsM:8CJ3m90G8fn .ʈOjP{Jș>*ZR:#"z醲IENDB`ukui-biometric-auth/images/FingerPrint/06.png0000664000175000017500000000700015167732630020025 0ustar fengfengPNG  IHDRbb IDATxMG$O`3D Y fpذ oy0+$DH$$2,ؚI1䚱s驮q^Uu>o "gDyMC !S oH>m;;L#")r|#ۉ"*"H[w"!;Cn􀮄Xʓ2U%"rPF/~ߴ =BfO݈5]RND?*XYȀ(KM+JGG{kM$ XF1)RI*2> >EEA4U$zqqﷴo$a[!DX}x}XUmAveڊDc;jQ >EWYeH9ǁo 0%FwHu{8rf q~^&\JԷ]ݓq*2jH(IH}5H1C oQn34:&& t;DL~_1Y5UIfo f eA( IuO\&!b#8Br*'%r+ُdX2>TToGt&G))2(#o<}BVU.*+SQY"jԾ9<|Mbʌ~ 8'xwA!gsPx6)qk Z}<圖saG\ b5ʽ(-0`nmŨzWBspl&} ~_~O̯y l[d#[NS8EO鱧ޏm[?PLSiqOBYHD1~ 3E4żo딫=wwL"1ժ@GGqb07^½k># joƅ6&< =ZN$# 7bz1P9-,Ym<-(*Գ( !Ǟw=y;lYe' `L:Ѷ;a_7s#7BW2ǝ/ VvYl^zY2P&ѰKM.{&Q(jIDzk:4 6TsDib'#82K5mZB'D+|y䫞[İKgx NCv̅Ц(x"#/րVin446gd%A&!(U[j+UčU9I&E=ݦSW!B@[Xa8jUU08쓽R:F GL"rXCD "XqZ2ݫjaU[xa TD^1%q#Ɖ̡KzsvZDV&2,I#iGzխ2ՠSj76Kp "r x*~VKSD- s׭f4ss"\CMI:pWM?0y]O|o3"׭n-$Dd''®Fy}Ѵ0?,([O Cٌ!\ !!P&/ݵTnlPPZ< #B M!7ט.zeo 05R;0330& a#{T.]r6AmZ]3I:(h6A N#UÜiF<vDX/-U9 .yb)A'TߝPa.shC5 8soBC ʆ:T|O!FXBtc Z˾R_tH]74m]a4gXj$gcL gh,NL̈F֣U-1L[rD,i#ud:s2*:!NYʡ qU8N?ɷ\ . G mM&QVZʭ 7׹{Zƈ(YC$ TO$U\ }.`̹TQT7Xn~V3"PWGBwMg_[A[^41$q'w9f#ǻe3&Qg{m~4ܬ }bѦjB{Bru`%lnFs%٤ ǰ:KyD ~^o\9t5AMA2kZAZ"S7|van|RE&Kd2ȇyjMS 11Dh|,;2[%,rΝ& xVDN(X'޽Fͥte{J+ kD׺i)Ԍzf mq`_@{e"M ;DbW̮3"fA~%djDžBhPὣV9(&5KFxK32&9,.bٖAab(P+;+B:'/UXI(\$yA iL[&`?%B"NtOBB+4VGKGj 9jŸ"%-_"?d&"rƩ 6!\pr?c;/cvN\qKe'=/"q;-@D!WE+%gd%IENDB`ukui-biometric-auth/images/FingerPrint/12.png0000664000175000017500000000717715167732630020041 0ustar fengfengPNG  IHDRbbFIDATx]lWII]&$UiA _j6TWR7x@2Rȭx ^PB$-EU nRM'9;3_Ν;=_B9("'DdʶdBD&[,p r{"2Md+;"2VQ6-Ddd;d|qn!mY;_DԪ#wm5L!ﯺ!ea;RN9"Dj=,p!ܖFv+nØ:IUhʶ,fIF;RfDGuj8jҎAS)"23RD$q)ibU"1u|΄_52bSA;NnN߳ ]ǣAU:vcUͮkbnPaaʘlsdQl;WHr3!ӺM f|6/( QJV9Bx"_Άd<窲ϢYsmkfBȵvnMk%< q:GSzfrfS!sGiN$z}BIB'{&2LU6,LS!tB\7=~oUoAIŎaus b Fx슙$k -ĘF鲹@&kn֦0&t'&#9zuCޅ1%2NH N4I@7$$eLC*LxҚp\FQ a,t4_d%L'UHɆvw-m}N7ٞFd F5Di,GDdXD۶ͮjVOs :jS[d%oDY+]6GD#"|HӶ"ﱲ/Q"җiیjC !\G=my`}gm95y;kw_~~ge{Vl'1tᖈXeOѵ5vDίEd;JB?i2>ge~kЩ'v7H1 C$$>imsVx?DJ:Qa*Y$$dM[ IX.uH[eU0(p4f6V"D@#%Ia+i%4 ;ٵF rߤIpRY1 V>Ӿ_EdX !Qdh @;P:I1Zyb2,QfxP<9Ip;s-$b&!b!-n"?݊v?bRvZk$Q+ QAFBCp|޳Y;VH4QlV[ D')9p6욡hU:e6~']˨d֞ !K(!2-p" Fd wE圈ZtLZ3|+"Gۨ;jHYѾDmt":,-a$ ۉ-&ı4qQG̿PN>nTLƠ] Q#v+hs}/̶)`#(MDXy Ffק뤉|=)L2.w"k]DjihFF)""b!fI~~ŽךQɂF&qdu;J a+HGEɚ<"<g}42SM)}nFTۢsAb"|MS6v<:͎fMM|WfsOBFnXF#bڟ9KH^%qT7PGה9}L 4> vYS/t,po_F.V>I!tl3bHvv>kG4q4 OG,-hv-Fyu99h(}CDn #";NN̶QO(?@2[y.;OcGo!^ ^Cqں`Mג w C$~'\x!:F%y@w;BکYkX^;g;[І(oVu];mar5ZZ;X+z劢DNZb6 " e"u%(\m٦vJ3DX~ mvM%+ "gsh<("ZvrgmnpjJ܅BndB}>fV>E4j*s6mr4GPէA`!"[Zx[*_FD]6. 4 +,= "Q K6HFCp'I"Y_*e&}g׮LD,8mc6JZ<j/"I?v|*rg 6"L5\)QN46:8zhuՂET ",Ӱ Y@ֵng=G=`iew]-BeD(jra A9vaCj9:hx40'~WBk|i".YmClgȐPj6OTQ2QV2g^n|x`V;;"r ҅iC%;v$ؘ/!}oOꚴe1n>?F5mpK:6Nj7$y餈tR/ǝ H[ɊU9osZɢJǤe0 $zeqJ2?[mlIENDB`ukui-biometric-auth/images/FingerPrint/04.png0000664000175000017500000000701615167732630020032 0ustar fengfengPNG  IHDRbb IDATxn]Gc;vcb%6!T) @m 7\'(%#GN]2H0Tф "b,=euB OBr\ $D2$7!DDBLXkECyVpf<{<_LiMH 9y[N~l#$Xf,l#e"J=v x$uHȕ]GLz|GGD֎FD( ˌmDVD'.UYY3&p B-(4ŒIXb,t{dhB*6 ^9R*:]~ \! ~VWܵ_$/:5"Bl#!%;/5k_fT@ߒXk~^dۀdoEdԑPmrrz &m|iIcCElo9Bx "%b 0t`*񖒷 !ܝsAC? 6BZLQg$uؚ'B%BbYឈ >2e`HՔ!d0"D<6Q(X=!Wmjݬ;*Kk.p;p#W^Pusy;;P"~"!zXi]U$-2ixs%ݺND։@IF/D$$I(ȤVvonImTXED$$7HPa\x.v~Ek[ev iFFDP/$>EƥVjBDNI=.@VC1"NΈЏB,{!OJXP{Ynm+חH,D`3$j!A,D\]h7sE:VQ}&>@D=^]F][X|,0xI>K|!B@O )61}*OgDrKl;}#َ)ީqxOdj](':jK=Ϯ֪3fEn߫B8 !SO5UoUFۢ}T*Yg (9پ:)ҽmB p*"e2|2tNG] b ]S kx1hV;GJ՝"ՠ_ nFk !D"|Mt:%Bla2wJ]`A++"YCoMg:p_]]wv]#LEFKE^ tKL';tX0oCDFe!;DX~[ѵEFYv$%=8p3p70Gn-$dT vw r^_d (-L"ALi{CԼ_LI`6+`Xj 4B5\3! …K.gȸKT]k<#X߼]QW& J^u:,s?M-c[#FDjXN wP4`&C5 oYi- yDlJC1Ī&y,Bt}E_ `BΩpH]790CkgXhƘn/d/,Y:{Z2Ad~3#^7VTa5bC;RW@W-b"\o݈|Bu]AG`аYAʹ6P7qb(4p&SXWA/#4:b(I["\W5?A'k=Eם_o׏~xC u'7ޒ>w DMVQȻ--ty8IENDB`ukui-biometric-auth/images/FingerPrint/02.png0000664000175000017500000000612315167732630020026 0ustar fengfengPNG  IHDRbb IDATx]AhZvЂ:k$ P ؗܤBC9عrsY| l  0A ,-dlFͬ_ΛRuutU+~_իW^U :_IH? l@ZmOҲ],[4p*nkcNrz(|FDg/|xC?Ä)/` Kq&UU҉fDK0}ɇ`>gf!a7!OJ [+HW Zo{'m'"1Lo|b^`[tKeD]8f^Wj&%SB5'OpG&=]`fY=aB .ʾ]QCi),k,9[ T'f!BF?~ Cbolx?%CcmX"Bw?)by#; D[o*^I3_SS)xIDm>Ϣ9"yc^pժDrqOXtB51: I|p&D02\ JJ8M)ހU}8|91ETY"DlŁ&":n!pd#L=":Yt5ϕ LTP߆#F ΣyV ؇#e#>U` dg`A.zy/ȗ;a5g.|^9[5|&&&y+:Yh>) |s5[E))%\_a1ޞ%Y0n U`6:s[Q*Xf>O)D|9נQ^ͣ*kF*]!N@}fSd爡u"du9])Y8akquhwR?86s5b⊛uh(@RM:1Sȥptn{p#uuS5WyqMP|L٩>:$P|n r)s׶0=u~U+ QcUΙb"Dqx5x71 UnM֭2&;+t/68scXӷ6(E7Anbb`!c,r&:@ĸˏ&W/MGM YQ|P ,d\ߺc(n5 Q>d.ޙmʂ ""_i"Lcb Dcgru ۫fRvtS rkD3o:Ifoko 14y{.ᖡkt /Pk|PYTkqRp 3U(#?r+yو0;k@K5p½&!|LyuvZ1&$+]"B1ӽ^LJ6}ULCT*g2Dƺ2Bs-saR72S[ٿ99"LZ@~RRd 1 Ԃ?¤V 0Hn|?L:3ʼ 9H͈eϵ;@]rVSj1{%U(FDSI 5GjLuBE 5=u}:tiķJͱq)&6ĶADx$$ycۏ)ޣ2?S! %Hnȳt K3W] }`VWɟ'Ta+}D\̳k̿3_7郢u_׃g'`ᐂ} WqxBmU7̟pg~΀A^2{ݚ!IENDB`ukui-biometric-auth/images/FingerPrint/01.png0000664000175000017500000000537215167732630020032 0ustar fengfengPNG  IHDRbb IDATx]j&666688DpHi}M 7#y!:(V罽n\![:ͷ;;;38` 3W,`r2O |U"I|3Cnv|/(ӽkG*۷__^fn@ 1:ni|.0c-G'bf" [FWs7$̼`%Dtf{k6lXޠ `@D_Ţ諶k ]\O&A3@z.ǞKFn !y.G;e2z|3,, v ^DtB2'9.v%B S3jB7bSHn5BTl FU}H'I:"&5vU=u̼̻efNXM GN\gn2QGjlBe;cqsxD5 h635.:E3oWav5<:7e "yroj6CѝGn!kaY.#*3d%B/"+EJgq݇`HѹgO_F9ɉPA+bdmnTn.cHi՘h9$0ŢmLG^ma%77ۇD(mɩs&7:δUT Մ 0 dԹ=>&rxFS*d!BX3O%_ -V:N_)$f\OTIL1c>ѦFHp-mt4a}ED9uڄ8[5HM!y+:Yɶl>wQX< }Pk,u{[oz3}Ŧπ苪? k"ToRS$# +pn+Wz1=.y@wSRj^^'6P i"u?1YL"BDh<慿!#Y[*jz=XOB5Y(S jBI4[]ႈ1o s(m]=J !sz7ZWd:$BCMnMfn;0_yV106i38$LRhȾu7OԽkY:?wɕQcUF9TD"q{z5xa: {^uFL<" RYM޸Z5qM߲`Dd:\&ڒRYNn{gR5ٮjDDIL}Yn 4M:M}P Rg^ߺCn5 R>Yg/Z 6%Ax=Rd"~cYkuY ܥ:E:)2߸YM\])9:CcʀJ: $9:&xM7̃쓵KD;{>k G>.!u?UZr}n1Yܮp(н{ZcռZσdD8k;Gz>є}o= IO۹`OXY +]auV &zk&"yucK<LCi*;R"d]\C1TNZGgpvRoCO !j+3:G鱃Pk)?XQJDKU }Y)4N=َb3}ʼqBiaNsR3jR80pO,=)}hByNjQdsC3mAf (j/ :J~q:ON}H9NsFFgFFك{K=5,&C,5.fd_Qw!*d$(>Du7w-}:0qI":gk9 ܕ`EFd&+z@E"b;Wc,efG~פ#?iRd;^fm_:rjr><|ǎ_/xq龲 Ժx]V3iP?3`O r)ƆIENDB`ukui-biometric-auth/images/FingerPrint/13.png0000664000175000017500000000704715167732630020036 0ustar fengfengPNG  IHDRbb IDATxoW?N 4 MIVB"UB,!X dv[CP ,T Z?H6]sXs6Ja7-{N5ݱ "rJeDDBݏ0HUR:3hOu+%`)@:Y,l7܇YM-^Չ:HCDm.Y\!KZEݵ!ZѥiHF\ٶ "$M]XRHJPJĂ ;ԈmIJ{~#nB;QC'>ACu߳ _g *NL_Эk&;hjp?g\Vi6s*Iq)pzٌͫ;`YSԳa,BDN^WK%'u OUǯE=w%Lc)#38$V!cN$x!9kdAPI=Bwjuc bFC1CȊY㮇tw?>%3a%fB\7fc݂PZZK9 +4( XE$]GeAk XJs-"c K ec̡%o0G~BxrGaf z_Ig +XN(VdØ_n!#\G‡ЇuHғ)Pd>jSF IJ#HY>î<%od_5O)|䶯// +zN(=};.Dvg%Kq ]jOsZ|}FG"&IW+䴟!aBE`祇cUDc I2YBzf륑{@q EQ?\C$=Ywwfus|dF?L DJ+rev}lBw#ɠ_P:j*R+T7N dI;Lmجo/y]-g:ۭc'BHETw#."IRC8a\ͪYirQV3/E 9-NK]D4JI+"t9 *"Dd[|AݣjHܳl2Mߨ\/"39Ni7^5DpG<$ɣ Y}N"lZV VaXQPam^s?M'c_w91C2 ڷIi- vG/Zu=AE|OgG5-L{C=wkq)`KtKtP O[?FsW_RNĤ3+^o$ mJ$ضal I(j{H 6$ohvFOm$1Et5Y"DA fz<63ϲil!O֎0"Ock#?Ȱ2ikDFoOĿu42ix(̲A"IG''EDn{qDH[ú!QȁN2fuDzZ-e$lqsMf~yo3n6~,dGDh h}s~ۻ,^nXr{ )B₼ϐ`gRO} O>,I!DB*Hg"2V`DL&/sbz^Ml6ed|\u(S*֦F):5?/KQGw1Y\jH?{I[$KM"|xL[!Ɋ|Dɺ<"N ""en+.007B<~G$`S(k55ukztj!Za"$܎`n\̈́n{Of;ĕY,&I-Xhg 1~t0,o#]O$._+#ڿl,}҅vۤý(8/h/poaQJZC2>k%9b\"!#/ 6 aݵ1% {lk{3m}r63 *lit{u9@н9)ݞdjѽLi?{,Fi=yn´ӴHlc 펮o۷-Ͷo}"#& q1uFAr=I|24M!,M\#q!nv%賔Js]%ƫ ؕdlmm 7#pks۝o "viFLcW˲ B&BӶWz.D5 ;}\QgYLsXM" U_ F OOV%C݋ wp>o#C%f0cYRx(p>6Α"ƃGH\uP槉ĽB͒TO͂6ΞS|`S%͹Aι-℀ib PZꀒ яŜ&H>fr_d~Jd|Hp 7D죓8֯T zxH.:+Ԯ]ի ,_5 IENDB`ukui-biometric-auth/images/FingerPrint/17.png0000664000175000017500000000645215167732630020041 0ustar fengfengPNG  IHDRbb IDATxKl]GvIRB Q! $R 6 a i%$,."_J( qR(얒o|3{mь=9Ǽ@D)YTKRR 9y#y7\qkC~!f͏+"rBDZz YPٮy?zhJǂqηYޔqGۮnU$I+?vEB5֊K&3hc@GyMuVs@7Idn:,hUX}Z"2k'5X%m紼^E{ӪΤiK+lS PNZ7ґ!%vh*y5~+fB9\EPP1/753@u4jЉЇoC@vzuZDك\݌U`}l̑F3H{1=%Ipjь;!Q0R!"G$9#d{ü&?V3J$8~ͷ\-+t1وxS׻] t\;:Hs"=Bd몑%BgOY YW*@C_1!dk㎇l[,:t_<ks HV\ߩ:c&C.ԭڗS c6Z u$ۏzt4v5BhB%;cW^xx0I.# 5M#gېw@TTRcaXBҝ1jo#R_xYFra` g}3n5YBݓvV`ASec 309wj tl] R0\ ifHvwtЯH(+RXI)pʦTm%KR[_0`ϗy33(X0W(b~bG."նU qi#oHj _voV E%MF>CA&w4-B ݐ ]R tJYyNI" ؟Z\mpߵ#Sхqe;<";y1y 4sysMց~s~Qo*ZUA@f*>{Q?5y!w#}vh}ZDok-;FPeh(<,6ݢɡ _*9t8h:4w$.euZ _-d搓%QTTǮ i!:'_I#NS暼0NqJőC^e5)عcqD;O։ * "+R1J@H^ JĊ3-|Y7!bW JU{D *r.]MA/pNȔifM 9ϛk&E$1+;B_0 (nlkӇxb1u? Jnclh I/bDhK sJIMS>M%n>zɏ#Ք$'}x0pT AZ";R6H&.sOy7pg fTCGKk΀I("2 瞐8[ s8a]!|zK :&= ρ_!>dx&;Gp&y<"m^kCHMׁY}NF;b[D<ǀI5f"(xn{+mrɭc8YS36zB6}ɯGrO=vmhH_D0M>)>$FAm>oLw0d Rs'+h7yXΤ:Vm"-DL ۖcLc/dl8d1", aЛmڧqQ8 0߽F\3ǯUՎZD( ӤDG%nk5~ 8/BoC6xxgHOU|ǔ.NSE'$XH&+}&]w?8b/2ME$I_)ݎ&I+;ؔy,c6$XbǴ[yQ<g&6 \t.{ư[UmpQ䛝;'jKl͇uex g .B+~3澇pfe8Q8R,/iͧ4-2GsaFgH^'T#D$Ԁc&I3a;˸1)+l:D="'k~-{P+2&jSfRd6p g f4tPQ!c!Qr兽*ԛ2ϫcٷDH[-8Q2VwՈp|ǯD+l_}!O+C8s0ky"Oi<ߛϛ;HȚ !tTW5SlKF^s/q/@G\-y^? a9L,{ /=GV|yX%բaBD5$I.Ӹ0yVLG>bgJB;qEyC'r4E"ہ6[ף Kzr I mM`z2?Yv"I)%KKS< t Nl9uߩ$n@M*omT|-z HIENDB`ukui-biometric-auth/images/FingerPrint/11.png0000664000175000017500000000717215167732630020033 0ustar fengfengPNG  IHDRbbAIDATx[]e;thZRjHX$񖎈KbQDc,&|DTbDLfDi Na)3sˇ}fL/g9"v9("c(k"2ڄ\Ed{Gh0c "+HCчc"r@Dto-Ddv,CǁǺf`86n "eٸelADv'@!=O ؍9O?Bxi5:z0l480 CZ2vvcg!vbT:(:A#Dd:ۿjK$3m3Aj5i{2NDSEjh 合Le1-hr@j$FV١XQD &2b&DԤhD3‰`7=!Z>u $jEDXP<5kd[PtaaX˘έsdl; Hr!e fmVޑ(:J#DdwEV:>ZU?GZ6 Q?3׶gzV"G24cMC4K i}D+o"K=Q3"dlZjaK 7F2rm!K #jK_lgHh#}b&3aj?[1&Jys 9>ݳ69e7G8#V Q'4v*5B5" fSSĮǁC?a܎0ׄƳJ4ڿm׏H.ŔOf\͏48o4%"Dpb%TDP&fG7{qmꗮ'jiG4 -Ql2&K{, Ǘ4K"5Gۓ$MeeuGF"r f9&~;/V :kD_l>u ]'"5HyHDnE$Dck{АFI4&JD }vtG]6>_hد|xt%_l}ɶ/ۀ=E>j-4fN"|' yՄ%:3VdׁOw !UD.3T=Tq?-9Tfd-'RulR v237=t}_[ ,5SxJ$x 1JzLB =۱h=OIiUDE/$Xod|s@mZd\οL!^9IX%˨̓Q*"RC "ZBDDc2c= I{W YۀM@kOP\> | _FQ"[mRYWHD cC$oA;Y='GH#wB<xl|J8e}3YGǺW!""}&]zs|>b=K N&4\8)40kwN+П%7C7iR>%݁FymBl8!(!Hi 0]$ 9f~1ojG+J=PsxR֧Q-ۃ _@.y;<[DjGSD }$r"|I&c2o'I,'GD\4ӨMa) n5@MQ\qnG㋵Mu#7)bg҇:TP0@mSvwuixwٵ@@MIT[3TkUm$35g(/t7 Xi_Bgn/O:&*TCz]hItո\`W[߱~N9;I40o}3S  #vYNzk@9"=MF7:OyUhhDlCgu[kQMMmalk%a I`mvO~-v5џj㋨I7I&?J7E5r654Xб}|Oky"L0k;:*p?/yބ,PMx#:}]6j+Lp!g <.Uam,b>Teuv?3$=e~uqZքG*Ns1( 'Z:ly5s$Ahf.Z.zxmMێ7 "2g8} LvuGڟǩ'e-,P=_wQmh?6)q5֯ *ѵI4Q>h;Dqc}\JgBsY.4rz>p>h6B84j;B8UƲR>`t6k_'43_[}kit bLMda7vw,4MӨ).Rau'//@VЇF>/Ջ絭ƴG;h,F'zyyE)r umN6b$"ݭxurW/4NZq#׌0S%.`W^2̼lF ZcF4:JXP8J:Q+}NADpliV#[ҝ9HLTyM(q2$M9;Πu!uҜ6Qm3k@89ꅪHL1ҏg6MWˆ덶/fPnQM!`4Ȭgl.es0%ۯ]w9QAFmoS7ft "}O Z*Rn[I}u_}z46*KDTE݌=C%2 F5!3+EgGDF`$ +/^nh -G Ϡ=J9Engq4y~U"JS27%̌EfCyV`Q@?&gY4B%TZ(fEM3< ooVP GGsO9>BXNŸ1D ^ޮYYmKl'rбDHUm!gԝL- i) >B댥cKmAᔈCMPn1:a/+k|fWK#?*"q;>\ސ,m=Ez35 QtO!G~p$:8*ߗlFIE-J,ۜfpV?b*5_8,-?{({IENDB`ukui-biometric-auth/images/FingerPrint/15.png0000664000175000017500000000670215167732630020035 0ustar fengfengPNG  IHDRbb IDATx]]W{f26CFՌ( 8WAQ! Qao *LO,*ڀ"3ik M43|k嬳{ϝq}s{ 8Q9+"Kb"؅LgEhY ]bmJr[H ;N.im"2]r>ON\Ja۸9KbD~%Ba򟪻"U;[Y~c䈐_i& ,‹} `n:kmjXR9Dg4X%z^G!jUhN\"jK- S#$N$qt?崔OI,JٴqK"B¯LH4N2ЦC'6zEסA? ^]'V }:Կ $͡k΀f'DLa 9hhdc+é.F3l[4 QOJV9BxQ#gɏT9M6WN>ME?ӷJ&8~z_s;Z+l3ąM!qt餞;Os"+wFe=g!!diZ7PA,%BBLw=dB^-=<1%+f14(_[hJͪc 9K\@=1n˭NL*=N^"IwƮU_F$Ni'Sɩ&vhP< oOk|?JsGL*\{Hd/6[_LB.bMy6B!=ud+tZᴡgPCtR3 _JFhz(1Xqdumעk}5WEJԛxl.r\2ޑQpNxB |nL Hgsv~^T„Z!| 6Y>)# $5M#gH~ڻT *DQ*biбdoƴU{GVp?* ݵhV0pz|yϕAcɶvw'P>~gs"P(ن}CH銂lPЮN}5@p& eIc/VRE8e׉{ U*RHdzmɼs3T`P$"T{uq+vqֈdfm#0ͪiNQ6fh tRp7;\gʶQB h͔ R 4:Оn3BSF7$.˟#皮oC\wV :\k5pNe_pBi^L@o+9oOZDقsOjls92AڽU:Mׅ% $DY-Z蝚7ԩO[^G7;I#f(' .ihPT Y:8CΤڠdsEcWb(D)2V$?:CE" D 6毈_Dd&V֏%u"Ϲ&>Ef~ E&|O㚿]TfUBꪡ}°L2m瀫"2Ϟ&5U'DyM0mMb"."j1緔-`C^__Emdd~< LRz}+bȈk< mĠ4f D4&KW"ODJQZ8| ,y6zRD׈1-`{B|{~ Lk,y2|Yy|AFķ4w7yz#D2HD7, !lB#{O>|~5\' 58|3m iC [>n($k~2"ZqxҺBOD`ǝ6g`r"R,+;dL.O >-"{-"i> pH('Lϫz1 h# "q־o!-"!*]ha?~bd`/)#cM?5Wd L< [^I)ͭF7DBnVՎPɄmTD'~KMdrKD-&Fm|ZNi2 ^ExUv\)5`fңLjn/q֎uM|ei9%p$x$Ik4GCm{ecDx88&!7-b;| x5K0oe&R4θxF5DI~0px"1,z͸hn*U4͐A.9VAz8ޛ5ȫpo }w(!-#"uཚc {ɓabO6…hi"IG6 1)6\[[Du'\;_e;7m10ygU4&sp>gfSa)<sE^C;`̄wz ~z䃄Mw:N{O+r)-RS "1 !,ehA3 NUBx q?k]u~bdPh"KjGr xڏn0rDh=L\qDwapX !\D !|gX}D!$ƬnҷaUCfLKCznT:\r^jIOĊpMƆBoWܒq,R U@Gvl}cv j#[|huLkξ_ "A]$:s4cP'>G!K=5I##Mq)z3p-Uʜ&jĸ<,#KDBj?#0e"MH_IHq?6BLC}?"fi6Bo:1_G]aBD&(0!cDc .DCB}?^0`2_-HM)?(+#N {xbyd Ԯ]ի|+W}IENDB`ukui-biometric-auth/images/FingerPrint/18.png0000664000175000017500000000640115167732630020034 0ustar fengfengPNG  IHDRbb IDATxMeGw3_'&((3f#JPW3u1FwE'E7  :4ҝDBgb33UzU{?\޻֫{uΩ:UuH:&霤2{;)c:ccϿc imr[ ;oNH:#ig۵eb}ޞ 8s] |z]*0,⩉Trn:,.tWIJvP0T!(GuʖWڴhS68LCbʶ`!B9/i#RWFSHP(XV.0ElVDxALș QXVC̉8zM.utڿ^gL#V̜P633 [俯܂>|װzeWIv W(EQ<7bLM;`wQ^Z;J#$()߳Hu4)GUAp'Vӏ-/sc͕\ q9);&;F+Ns'&iN"DF5YYW^+fb$AF]zėϼ59E\O\vLÀ܂7PKH:{rަ[r0۴8UnngRFD0N׵4SC3vuGq1L'ݱ-,hJkmߐIڎ/GZrڡ4uʱåu92=0Nx3Vqaٶ9v~Q.ToY-nS4 USɞSƏՆ?v䲟mCհwV ^Ey.10KSp?n"h42uYjw6yTsm)TBX1hjU.RM"QVs$m4Q3 TÝ57*~uBYQ{4bOTM#)Tm$K->,[k4(FѬׂ4 u+,aua!@ne!0K*ׁAo-FtХ~]1M" 8\ޱ\mpΐ޵# Y;6wZĽK9"1S y4ssxx| W sqhoݪ[B@f-?M} B&}eϜ'zߺ7g}z1qak4'p}NӴ]X[h "Ÿ×S7ZeO }jc!MO e4iܠ"|wsÉK>6Fk3}qS gcmScWb&DiJq$k^=mԈȌVH.W$M#9 uTEئ[79TY}ݢȩpxth6Dz:mu_-49lG@ Ǟ贳hC2r֯vE 7u*ǭE>sr`rj82kPeI/6TsǔqL՝EuRCPqOf[c<1yu$k'*+rӝgZoB Zk!ujr-"&\ktZPfL=K^G6= /Ni-7E J(Ug`70)%BpN!]OV_􏀟QЕKB|g> o'u "x(@!..biLF0px/Ug%%>+9nGpTGLL.r7G!~pj_g7:}[8_pTGu.\T5&chȖ!䉈I 머q-ஒwl[WuI8- 댒2C#-ߤqrmMD¶)I`B>qNK㏿ey16p_IHFl7c,"< (GK\l,!>>z׫yxOw {qtԗ} d0-[>i"HObMV.Ӕރsր_Q}6TI`7 7Zf"[2*sdt"`IH}nҚ$Ju|AZ;k[f".wML&;f D㴉&8'nqL;Z|CpɋNt3jF[rimvPa[vlzRZ#89#VH%ܸʽ//&ܒY[~~JG5 -"|˷0x4Q|NcR WX3bc{D#>)16CmܦZݦ kQcp%ُ.9qz "n3i/R>u6΍mEX񂲄( u#5w!JDP5MGpa| vnĜ ]f$pqMEl(<6)q#6kw*XkW5{8VQnk[ ʲCZd53|5reַht{R|}^W4.߭tAz=rxQ; . j \PΔIENDB`ukui-biometric-auth/images/FingerPrint/05.png0000664000175000017500000000702315167732630020031 0ustar fengfengPNG  IHDRbb IDATxϏG?Ńlpb @!qp  wr8p $$p(,Ll˫8z֏C͏|VzիpK"򖈼[]ܚAN&׷DRQ7fH0ŗ-@D>]@n7nuѻ}c!"T8y ;. %p븕"D'"}9."9)"t[쾓qM'"& "OCtPcm=w| no4i;wNCPBϦj"}`+%ZM}29 $&p$~`7m[r2zdd2: vl70b%JѱڹZL#D hɰ+U p^y>  OSH핔,&ljB}rR?d~߀Pߞ-̑A#)~j~ :'/[gC 9ժi _|ֈIĖۊ?k)!rIMc)Dϥ:I#nwH Qr^_~: '%0G Ygr#=M+bO&)Ytˀi75uY05}6S5㉭5ה#b@&tI%_k"unD$!C6YM?d:f;*m3%a@&l#¶"Bxzdx!!|xXAfL|Y5%$xUVqz]2&J5 ~o慜 i2&1jr$x$j5sy乻EdLz$x }UMQG=7+C"B25'a#*ZM^JJSt &:K)-Lsx˿OFF !WKITAfLJI[!< '!揽S`7=y, ?Q0.驐N6pArxr'~w.mm!ch]ͮ{s(!gFDZDNv8 '$ۧN;|;L :fTUkV㍰'\;㯉}'zΎ3M13ig1uzMT;&Tj!$Sy"ɾcOF^ \w}Tie1|Bx$"n$Q՝%kivagy,ΈD B9h8 2BF!'M]։PA\&k#~q£6ahU7"m!d}]"!KQuj.վuUSV#aDJFuUl h;IF+D$$I(}IYbM[}b-ߩ">i3UE OL]Fd>~ECbO2;>BB[qE?&]jBDI=N@bL<:/sX#BwJ@&=}5E2MaᐂЗ$}P4U&y%=OSU 6Te/ "WN.ڮMb-ua|2övͻ_NPPW"F;hVB#S. "Rٟ0XGľC78Bd2ͅCYGW=`Ԑ_ګ5bQ!ED\!Ji;;DPm?4 Zc4hjk]֭w !#U/ VS*X6QeoΓhFf[+ubpa/+";N !<u`("g4jEXTsH1qB87DyL9q"D,]Mb 7[Ӻ Cbqq:NhAuu plxYrBxĮșPn&EFkE^ws@lЮ[I0oSDe !Ȉh{& J6JD6:eyPuBvBc>S5^RB),4F>PZ3͑{!r kK>lVV=?30l& a.\r%V,`dqJ4ID]f '؄5U2T۠aP(LD E ]*JA)2%Y,z nRX"`6[Lr.K: xMDϻHftnsSݚ/te= z' u+qΌunufq1Q%tԽ_z׶Oت V{ W# NG+?j9מ/Y{;u;wI/w9"Z곃oc<QbZK7ݧ4.} ?dj*g`1CUq,.jW>nOxBjku͋#X _)X6~VڏX#A8Emc`9ҙ&oH{/4N 2QNQHEd0w%Di!:NVhGK3]E1ovWoc?C7eya2NAD;_7[GC+-' 7e~:G"Yq(k"r{lW"-"|:uۂÐuIENDB`ukui-biometric-auth/images/FingerPrint/08.png0000664000175000017500000000715415167732630020041 0ustar fengfengPNG  IHDRbb3IDATx[lWm;vM۔ҖH$R@ȥ\@\. B *oHx@B"6%MFvŭ]'v,Z}3sxfNh3g{9Dd< "l)Sr}@Dpo'Ll3]modн]]&?:4u#ı+qV7yhY醭7&AD nz醔%!Xe{=G}'I[:=Ap8B8&nn.s^UCޡ7!"1[8AғLtTFUڝ?@GK#ly9"DS(DlFO= WHz({$?%_bYua8Y~#jBT>ǫMvE^fXDQQ;v41@Tm>:]t tC^s nz `QGImga$8Bx]0ofep\=塧FB8biDKV_ lI_~Bh4FDH:*ۀY9Ym $F p.o~\.Zy)p{Z j%BDЏ sxUmQ;)>k7&$P2r8>swX%߮cTNe/_xxDоĽYraࣶ\cu |x%JFL%D z\ 9V0#_${n \|00 |39$D֘5%BD ο S/*˒""b|jӨ8ګd߶BbJcM2Mt"q1k1uqp^B{jLBI# KrVˆ8^{wO*eyIM 뜏kK]'m\Nzd :* !,9f !i"r 0>_ }ZDHcNf`TDBgmG5F+gB*XGb,P[DvX”kَ"TNh2=Yv4Hؒ'<۳~; Y+G{թ< "#`T=vl ſ/BB8$"[ GJQ)&!TIu繞ED >/taΈMURpS7˷抩f;mu}v T"T$EErNQH%F#^'Kl±™\\?p1p,a7SmHS(ef]5*#P3Il^¡¡kH뾈N 6k8G*Ppg \R0v;286kfa>u*(+`T`+O :\ڊ]#{i1sQ{B=rsFĂCuFӞDE5&%4([9Uߡs!gtHYwu[4MҬ8S#E6u{ kxEY~ SK.ș܈卼GVaB#bv\7ZE#D Og%j-KG4A25vjlZX/S !5>Y=7t_#%N/碌Dv)|=/wD? ӈrȯ'AIENDB`ukui-biometric-auth/images/FingerPrint/09.png0000664000175000017500000000705315167732630020040 0ustar fengfengPNG  IHDRbb IDATx_W?gwIY61iDڤALbUD_| } ETA XlAll)64%-4)9ܹ ̝;̙s"KD ۪"r9\]E 5?@DNBnGoNAгY~D$񛎃 uqmܺMAD]}d6ݱk?DDB鎭GHUƎUx^;"D}ﶭv3]d/n>U/qD(:N5#Dd :ڿd[d#OUQ۠Zu5ir.? ioLGAqWhkKY֯ U+j'nzO_fvt5 @y,4lkY4,YqyǕB|'D 8|7>m';{߷~}IQm0j%* vՌ>[ˤtC|'[td!` q52-q]DFeD\&gpQM('|-t.Vt;{Qh|Lπ?f̕䑑>GNo4Wmx*HH_;^cbRvNFBU2g} 6CַZg"" ₿5IC)?,K0i^5wHIps) ?wGeKs2t2'bLq)C uEx{ι mi'mhT>!:>ZEdvtF0ߊq"ƀo . ߵH3b3И%w5s7tYITk|~GhkT|QXy&+>~MflN3 xpst~#~ 6_GC9^c2ZoGF%EI.iըA3pbŠ#"2ZO.tnڻGOkrGnއD"ef-cGůC=LFBLKv~cnLFlS!UT7%v v< MމfOR-WO"##7 Nj#;% k h16<2b!$C^. ڂw2'o>Vm8{y׃de%I8hBلݾh&?!k3-wC46Z +&f,lM]x -Gdl.<'_o#,7s19)PyX6X[lf+~l|,אx^E v2'r\D&E/zN7v] ӨޮwH]D窷C AVkv6ɦ ܎{=ImQ g駈L|֮f]kg"X&FEdшk z^/B^ekk75y!c&ldRr|}J,Z/%cS$}H1K1|DԴaBsHUoܴ!"㨰zN /9T }˴@?eedEө6X\FP CI+l%Q(+5CψrN/M-wMwe cYxW4͠-uÒIm} !~Ĵpo4ƈ&F0is}dt_\v vstZĹv\S ! JBi(jĹ6A۾Fk-+jD//25-'5ŘFwMh -4MӨ)FW_TRa>*OJ̗-g+}YJ+E_LP,]O==vP:-mMG,C GNKe+"(D3h\m/~ݿ ܊FGt}&mbȀ[EdSw\wP8P.r˼kɾ5{h.u-uƜjۮzp-s(/g#ַmVWڈ1[w6~rT7HaTeR42j,`LSzͬ/UM,{x s_%"uӨlFx8i/";O8.5K!;vw¤QY{QBcخts-Qu;ٷNvKXa7J j.םeJ1`m䫸_)97A?JC_1,A=Jl3_e?ҕ&'j_TYO1&gee,Aa%|"4FD&P2]u5ADR86hx40'S!-/9}}MjmзD$$Tvv"񌺟"* =~*j(so},{yBmPn 14ډazm }?mkc!"ÉG溴nqG\ke]e~ȱFѡc<<"}k6D>^pXV# =WH)5_Z*&k~^U<*ɟ mK_CrIENDB`ukui-biometric-auth/images/FingerPrint/10.png0000664000175000017500000000710215167732630020023 0ustar fengfengPNG  IHDRbb IDATx]lWvčۤ)R(U@DRBB *T"'PT@<ʗ@4IrڄDmƩLJs쬽FwvΝ;=wv"ȘU8"2ނ\GEdc-4Tg "۱lcǣ'E䈈nZAH㓎#5uqmܺuADN,>qz7OBc.;R !=Gh|}8d.Zm`8&BgNv}8h!Nb\z(:N#Dd :?g[IF۟2AjTDSq'EgHF(G8%1.EibY"1= 3!jOddBI?N{IѤזN߳ _GAU:vuͮk ]pݑwBÚq^3Ȣ$ SUi:M)iɜ bWC''C*_D ) p-hBǗ5m䜕~]о=_h2pɎ"$,=/$dQRR.t?@"YHkHϮgPL[ǁ;/CBT^ͤ6r F//PFFW>vc5܈F5; |oC7V&m!"",^>:+$>#KF'ddCБ}/QHEvVQU򅿈%dE5ШYAf@:L]f$,f#h0k;J붿Hl\E:JHhe"2ZD F]W( Y8꼿ByDġHH2 G ~t/#oi֗YtBvҾ# h< w w?V/Dm>[ ̋A,IesV7knt, ."{QaB-@TQkw6Rr&|+lF3!s*:+Vr< "{EdyF#nhmX;>FJ+V oT56V:Lι mh\D;U'uʼ2$ǰEk;jVځ:M3kf9snڹVҌ蕚'쮠Ne?RU@nk7-E-DX9U6[ٌ*Z&β|+8{ƝwWW.GIGIțm~-(/f>c`% |GK7; cYxSiC;]8b&ii>A1-z?1,\݃ n&_D1׆UQ'jKَ#_)1vZ9G")7q%uZ0AmECvx%45\ N^h {BojC&_$^>j_/C"mp"A3.8BhF^f=n0URa!JO@E7B=+KnI,Z">ѫ0vjP--H;RԽ&iK%GV!x5+FOaIުdyَWp+Vׂ!ё;fQŢE4jd;P6z'i cއZ!7J2vtt Y[Rniۜ;?ȹh,T Sk[߶Yx[iֿthv=jPt|/\a]"RU X?; 7ͬ>WN29\Eg痪׮XD_AmoKft3˭"]^Cs\Bjw`#r'I=یfg۱U;T ",ӰH2nϲ{MQ`M䫸_)9^nMce"CMH[Iÿx/=CBEd х4wSN{YaS_!_qҺ!+'H\z2?9utǢң}3x$c [񚞫vH洂EUTg իߢ^<IENDB`ukui-biometric-auth/images/FingerPrint/14.png0000664000175000017500000000673015167732630020035 0ustar fengfengPNG  IHDRbb IDATxoW?׻qi"ƢRi"Z $Px'?H?`xA)RēRIjKڤ v4='sfvfwƻ+fsν{~{g "'D䬈,VKܥ r2E.V0l "+m1[9wrYDΈ|C}۳y9p5PB ݵ~);w>d "'U+AD n醔Zђ/ޫ=!1>,~NtU" !2F a^ShWubI(;F5#DQ۟-UMe4 Ѫ.TNZqew`!q 圈h}-I)XiqG"B:oMHt3JR"hȉ8^8u{SZȉЛn@u C6܎ĸ#fNN2BhZٌ-;`ES3㒥a,BDN^yңዙ-s\UvQφǯ=Ic)c38$n3B:NӝH=B%`ObY[X 3B#95yHbjo IEGar b % eW$YcXxmC(uʎ%D,qmԤ-esh`Eb2VavXBF/M? |#sCzŮwBq?dc 0eI̤N\N(d?Θ_Sn)#.m 224 g Ξw=;vC+EibP2zv@n)bőQ,}' 1oI}5E ;xd m9m̨*\,5kve]8M$ K*_ߒPtm=ihkJiIxxLbZm,. p(Y vQ*<<&qZEt"!ɛ1=ޑU8OHxa\ a-ԚΚGI^\#$oOB󺕎9>n =c j$ DzLWevml~H2K(R}XIMx $,Ibi=06Kd^_9rkD P(s~ށ\Dʽ:;VqO@d5"[ 'ʣY<+2Mec^bQu>Nr @cP:@'K>R ,ݳ/Ti_UIDY[Պϑ<]߆ oueʐ5pNisbkA\lSpM:/|u`nuh=:ʠWz=UB@ 仝zoR|MCgB7'ui"9"ODE䀈mxRlLf;翠uE%"cu~ KDdhcD[WDypSˤn㶞`'^?H !0&F"%=2pXަm[z~Qv-oҨia[y=', A-R !Gsk`FE ;$DL$cT]S "2uI>|xZHƬ" ,Ot[ ־->$l-ϒOCj10I*g;n657[6-`oo%#ZU)=~(;14fy$l%UrHo["lv_C!`}D!fq H$ɻ6QL,ik=~]xo-bMsx*a " cW_/;-f? ෤ʒmY$D? FmD̒Xo~ߛMW5)& w] I!Dm3*<(Oks.Θ,31_&\O/|#qeSH#dHH9Ddv yZqHKbcGkskD"ZE@Imu$7"|.kPImDVD'Ry$_o6{2>>{H`1Zio`o8@:7+0iqJFQ ^yx5MԸG]î??u/IRW'$-fB>kzKoOKQGw1YקKubZ8 |/Ān=ߟj=6{|6NY9iw5y,^.uȏ)mԬ6 =!;D> vI\$n\͔DܯK\,MBF Ev,!&ħI~`k-`K;צ;51U!j~~H0k{{{&pmi[.&B烼>tx: v$A gKw; -qfoyԿM 40 {V 8dد'MH6ZW/瑀ؓ1uSW&|;到nUrĢ"2 B6AH|`?_LG'>4ň>qX}ga`~`2?%W>$8R") IwIWKNދ{xU1߼os\QM2o I_8/X)n5IENDB`ukui-biometric-auth/images/ukui-loginopt-lose.svg0000664000175000017500000000232615167732630021140 0ustar fengfengukui-biometric-auth/images/VoicePrint/0000775000175000017500000000000015167732630016730 5ustar fengfengukui-biometric-auth/images/VoicePrint/16.png0000664000175000017500000000237015167732630017666 0ustar fengfengPNG  IHDRbbIDATxY0x6 p':t $ t H'L퇜b$dayxtɒy(M@0mQO^v0X5Oۤl{%>[op.uc_8c`|WދqR DD];6D\u툱ƞP6åJ}WI1+o* wK6/u`!"N+"Rgr̕1Jhu_H"LD0!Hm!fDD1!æK:u 7Tq%^d(s>~vPJ-ck) ~^_h&fKD&VWf)*O QDtn[72A#k{mBÙrSfP%3 l{DDDD!}WoD`DtED b򧑋<">#GrPևE{BX=nSj\"tҗIN fBr93WW yLl*&{Ꞩ !fVb:FY Fp?{R>Žre})Uj[v= HQl,܆9JJzМiIENDB`ukui-biometric-auth/images/VoicePrint/03.png0000664000175000017500000000234715167732630017666 0ustar fengfengPNG  IHDRbbIDATxq8w=nwt w`]59l++6 &D& `ЮͩSv5NféDFLyۭ7F1"F'd^`vM;!ڀv?Sz"kf-:ƦP'fum! "DepܽFJBxDtjMMS ?kZЬ>H}nkԻ&B7l@&`BdB۪z%/@xh5P}Es'M[̟ܐz>OB }*c QCqh ֮6C>MMBҵ< ^ktb 3'~ir"l瓆CB,$ aB$!DT^xȆtBLvu6H9o_&;Ӵ!Oӟo4p {B0/$b 25D51B.h =IR.BƯM%1m3pw豟W&LL0!2"LL0!2"B>vò!8 Igw|h_M0x>s~`DGnPwz,ˁkp*J޲({>dCxFkΖ`*PIENDB`ukui-biometric-auth/images/VoicePrint/07.png0000664000175000017500000000240515167732630017665 0ustar fengfengPNG  IHDRbbIDATxu8g{ \ l٫l* `+Hx+H~ hda}(Y=kʊF Uvrz`rࢅ2dvB-Ɩދwnz iۍKE]u "Əq}i^]`*m@Dwƈk+bB F7\npݤ4~DCeM7]dqF(`zG{N34 9Ć-&zǻ3İ0!M!)ݡ ؟ѽ i{hhԜ@1kGО{e?F(F GeC#HU!PLf~v2Ssh 1U٣-)3e?F=Si`ͱk"`B$ &D"-ĚYr;:lOklSHp/-߻|U^wb{ڶhս3Ѹb( |뿷gڶGӺG51D O{.D2K#$m88ՐU;/xWB;:༼&Xq͔5'!O蚈-]f Q%3T!Rb{`<ኙ﬈#2)":[7R! YkM㽑IvIsyVGyϘCSYzZ5!A\lCVB>n#h{| Љ1|akԇ&B3l@"`B$Q!jFNt?jGM25ެ{Gͱ;1`_.LS! bVh2E&]g.Yl7eԅ[%OTWk Fe#B;% jyҲ}(49^mCB̤$c=„ħ! W5|IvMz"d] T%kg4jo]Z {*456±#J{DB-Iqњֽ{LD%!'+يĞmP&)Gȅ1Aq7!wuLvFy:am1 1 c+pw豟&LD0!H"LD0!H"vB>Y93)Tnqmhi OY Fp䃿{Q`reV=]SjԶT7G[(nJgtJǤIENDB`ukui-biometric-auth/images/VoicePrint/06.png0000664000175000017500000000236715167732630017673 0ustar fengfengPNG  IHDRbbIDATxY8gx;t t*`\*[lU@V%qhday(/H?Ҍ%Y!0p `-hX'Wf 0X-O'}؃ hp%uq3pY'Ci[^7`S\yMWgC(%tc/hpnqJ &B{ZFw ubX7!M!=S(c?{Шj.Rv#6тRҿ1n|js:*+6&D" `n|z$(RB9 ؚ4kX&D"`B$ &D"h HDV9 r+:ltHklӀHp/ ݠA sm[?h=(QMyKpW*m>Ѣ&fAD yy+BNB>L :I^]FuDyWf?p^6+9s"D`+ Y^ݜt|Rl/[E!\u>t!Ok a!k]ӳW/ɺ,iA?2O"t+_#Sy5XBM O ?Z ynil_-lzj"t$ &D" ~[Uv(t?&]U^9wҴnǀGf@ ]t"o3$$ZrGx>t&gZó]5e8\BvA='o V߶œ3$fFDPDXCBd&F[0!"GȄ!PH:pC{ܑ,0 iYg=AT8뺦WF8Z[JD߇(\wP(2 =!' yЕuGH4QCE](M;M%5 hm3pww_d[N&D"`B$ &D"`B$ [!l u~FlLLv綽[|\o?loh1sogf(-=@kp*ڗ=bQot)v 7[~=IENDB`ukui-biometric-auth/images/VoicePrint/12.png0000664000175000017500000000236315167732630017664 0ustar fengfengPNG  IHDRbbIDATxU0;l6N@;A B'N:tN:<Ŋq'ѓ~pJѵdIq<\X_S4P[ԓ+]E^#d|@͊bދ S}\vcqY8]aS^7`CX WG]XƞP56ÅǍ cW 1W6y1 /;Cf6ˈۗO:sXL "v쵎Wk j'̰n!*FM#=C(ݾ ؞ѽ74꿘̍21|f9jОr>F Ge}#HU#Ofq"iχGۈ+|>,.(7†hwM㭑BPQO+OAWHm)􎙿^;U]h_V3BNϺ4{|\߉1|akԇfB3l@"`F$BhwjF6?Tdjޤ{M1U(u%)L1F,dsC 4TvpS3P]kx2}K5(/YlߴЙmbZbZڻ&gF>qeDR ґkfD$Yw\|W{_+Ph֠i (]556±"jwQL$i}"jO$t[F0 يA  .FH3Hw,%) m'2V07JV 6c? m;M"`F$fD"`F$fD"l[ǯ#ʧj']fL$]Q\gw}ݛ5^?g7/xmw:Pm%z݊2"E~c6