yubikey-neo-manager-1.4.0/0000775000175000017500000000000012621055514015237 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/resources/0000775000175000017500000000000012621055514017251 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/resources/win-installer.nsi0000664000175000017500000000736712565343436022603 0ustar daindain00000000000000!include "MUI2.nsh" !define MUI_ICON "yubikey-neo-manager.ico" ; The name of the installer Name "YubiKey NEO Manager" ; The file to write OutFile "../dist/yubikey-neo-manager-${VERSION}-win.exe" ; The default installation directory InstallDir "$PROGRAMFILES\Yubico\YubiKey NEO Manager" ; Registry key to check for directory (so if you install again, it will ; overwrite the old one automatically) InstallDirRegKey HKLM "Software\Yubico\yubikey-neo-manager" "Install_Dir" SetCompressor /SOLID lzma ShowInstDetails show Var MUI_TEMP Var STARTMENU_FOLDER ;Interface Settings !define MUI_ABORTWARNING ;-------------------------------- ; Pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_DIRECTORY ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_DEFAULTFOLDER "Yubico\YubiKey NEO Manager" !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Yubico\YubiKey NEO Manager" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;Languages !insertmacro MUI_LANGUAGE "English" ;-------------------------------- Section "YubiKey NEO Manager" SectionIn RO SetOutPath $INSTDIR FILE "..\dist\YubiKey NEO Manager\*" SectionEnd Var MYTMP # Last section is a hidden one. Section WriteUninstaller "$INSTDIR\uninstall.exe" ; Write the installation path into the registry WriteRegStr HKLM "Software\Yubico\yubikey-neo-manager" "Install_Dir" "$INSTDIR" # Windows Add/Remove Programs support StrCpy $MYTMP "Software\Microsoft\Windows\CurrentVersion\Uninstall\yubikey-neo-manager" WriteRegStr HKLM $MYTMP "DisplayName" "YubiKey NEO Manager" WriteRegExpandStr HKLM $MYTMP "UninstallString" '"$INSTDIR\uninstall.exe"' WriteRegExpandStr HKLM $MYTMP "InstallLocation" "$INSTDIR" WriteRegStr HKLM $MYTMP "DisplayVersion" "${VERSION}" WriteRegStr HKLM $MYTMP "Publisher" "Yubico AB" WriteRegStr HKLM $MYTMP "URLInfoAbout" "http://www.yubico.com" WriteRegDWORD HKLM $MYTMP "NoModify" "1" WriteRegDWORD HKLM $MYTMP "NoRepair" "1" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts SetShellVarContext all SetOutPath "$SMPROGRAMS\$STARTMENU_FOLDER" CreateShortCut "YubiKey NEO Manager.lnk" "$INSTDIR\YubiKey NEO Manager.exe" "" "$INSTDIR\YubiKey NEO Manager.exe" 0 CreateShortCut "Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 1 WriteINIStr "$SMPROGRAMS\$STARTMENU_FOLDER\Yubico Web page.url" \ "InternetShortcut" "URL" "http://www.yubico.com/" !insertmacro MUI_STARTMENU_WRITE_END SectionEnd ; Uninstaller Section "Uninstall" ; Remove registry keys DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\yubikey-neo-manager" DeleteRegKey HKLM "Software\Yubico\yubikey-neo-manager" ; Remove all DELETE "$INSTDIR\*" ; Remove shortcuts, if any !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP SetShellVarContext all Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Yubico Web page.url" Delete "$SMPROGRAMS\$MUI_TEMP\YubiKey NEO Manager.lnk" ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" startMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors startMenuDeleteLoopDone StrCmp $MUI_TEMP $SMPROGRAMS startMenuDeleteLoopDone startMenuDeleteLoop startMenuDeleteLoopDone: DeleteRegKey /ifempty HKCU "Software\Yubico\yubikey-neo-manager" ; Remove directories used RMDir "$INSTDIR" SectionEnd yubikey-neo-manager-1.4.0/resources/osx-installer.pkgproj0000664000175000017500000005543612516377103023474 0ustar daindain00000000000000 PACKAGES PACKAGE_FILES DEFAULT_INSTALL_LOCATION / HIERARCHY CHILDREN CHILDREN CHILDREN GID 80 PATH Utilities PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH ../dist/YubiKey NEO Manager.app PATH_TYPE 1 PERMISSIONS 493 TYPE 3 UID 0 GID 80 PATH Applications PATH_TYPE 0 PERMISSIONS 509 TYPE 1 UID 0 CHILDREN CHILDREN GID 80 PATH Application Support PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Documentation PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Filesystems PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Frameworks PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Input Methods PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Internet Plug-Ins PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH LaunchAgents PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH LaunchDaemons PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH PreferencePanes PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Preferences PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 80 PATH Printers PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH PrivilegedHelperTools PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH QuickLook PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH QuickTime PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Screen Savers PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Scripts PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Services PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN GID 0 PATH Widgets PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH Library PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN CHILDREN CHILDREN GID 0 PATH Extensions PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH Library PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH System PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 CHILDREN CHILDREN GID 0 PATH Shared PATH_TYPE 0 PERMISSIONS 1023 TYPE 1 UID 0 GID 80 PATH Users PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 GID 0 PATH / PATH_TYPE 0 PERMISSIONS 493 TYPE 1 UID 0 PAYLOAD_TYPE 0 VERSION 2 PACKAGE_SCRIPTS POSTINSTALL_PATH PATH osx-patch-ccid PATH_TYPE 1 PREINSTALL_PATH RESOURCES CHILDREN GID 0 PATH osx-patch-ccid PATH_TYPE 1 PERMISSIONS 493 TYPE 3 UID 0 PACKAGE_SETTINGS AUTHENTICATION 1 CONCLUSION_ACTION 0 IDENTIFIER com.yubico.pkg.YubiKeyNEOManager NAME YubiKey NEO Manager OVERWRITE_PERMISSIONS VERSION 0.2.0 UUID 11112783-0BAA-41FF-86B4-F66A411887E9 PROJECT PROJECT_COMMENTS NOTES PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7 IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250 ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjEyNjUuMTkiPgo8c3R5bGUg dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5 Pgo8L2JvZHk+CjwvaHRtbD4K PROJECT_PRESENTATION BACKGROUND ALIGNMENT 0 BACKGROUND_PATH PATH installer_bg.png PATH_TYPE 1 CUSTOM 1 SCALING 0 INSTALLATION TYPE HIERARCHIES INSTALLER LIST DESCRIPTION OPTIONS HIDDEN STATE 1 PACKAGE_UUID 11112783-0BAA-41FF-86B4-F66A411887E9 TITLE TOOLTIP TYPE 0 UUID EDABC34C-552C-4359-ABE7-D9A7CA388207 REMOVED INSTALLATION TYPE 0 INSTALLATION_STEPS ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewIntroductionController INSTALLER_PLUGIN Introduction LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewReadMeController INSTALLER_PLUGIN ReadMe LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewLicenseController INSTALLER_PLUGIN License LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewDestinationSelectController INSTALLER_PLUGIN TargetSelect LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationTypeController INSTALLER_PLUGIN PackageSelection LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewInstallationController INSTALLER_PLUGIN Install LIST_TITLE_KEY InstallerSectionTitle ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS ICPresentationViewSummaryController INSTALLER_PLUGIN Summary LIST_TITLE_KEY InstallerSectionTitle INTRODUCTION LOCALIZATIONS LICENSE KEYWORDS ORGANIZATION organization OWNER Yubico AB YEAR 2014 LOCALIZATIONS MODE 0 TEMPLATE BSD License README LOCALIZATIONS SUMMARY LOCALIZATIONS TITLE LOCALIZATIONS LANGUAGE English VALUE YubiKey NEO Manager PROJECT_REQUIREMENTS LIST POSTINSTALL_PATH PREINSTALL_PATH RESOURCES ROOT_VOLUME_ONLY PROJECT_SETTINGS ADVANCED_OPTIONS BUILD_FORMAT 0 BUILD_PATH PATH ../dist PATH_TYPE 1 EXCLUDED_FILES PATTERNS_ARRAY REGULAR_EXPRESSION STRING .DS_Store TYPE 0 PROTECTED PROXY_NAME Remove .DS_Store files PROXY_TOOLTIP Remove ".DS_Store" files created by the Finder. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING .pbdevelopment TYPE 0 PROTECTED PROXY_NAME Remove .pbdevelopment files PROXY_TOOLTIP Remove ".pbdevelopment" files created by ProjectBuilder or Xcode. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING CVS TYPE 1 REGULAR_EXPRESSION STRING .cvsignore TYPE 0 REGULAR_EXPRESSION STRING .cvspass TYPE 0 REGULAR_EXPRESSION STRING .svn TYPE 1 REGULAR_EXPRESSION STRING .git TYPE 1 REGULAR_EXPRESSION STRING .gitignore TYPE 0 PROTECTED PROXY_NAME Remove SCM metadata PROXY_TOOLTIP Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING classes.nib TYPE 0 REGULAR_EXPRESSION STRING designable.db TYPE 0 REGULAR_EXPRESSION STRING info.nib TYPE 0 PROTECTED PROXY_NAME Optimize nib files PROXY_TOOLTIP Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles. STATE PATTERNS_ARRAY REGULAR_EXPRESSION STRING Resources Disabled TYPE 1 PROTECTED PROXY_NAME Remove Resources Disabled folders PROXY_TOOLTIP Remove "Resources Disabled" folders. STATE SEPARATOR NAME YubiKey NEO Manager TYPE 0 VERSION 2 yubikey-neo-manager-1.4.0/resources/yubikey-neo-manager.ico0000600000175000017500000007204212236453657023624 0ustar daindain00000000000000 hF  00 %V $9:(  AAFAAAAAFAA:AA<88AAsѪ@AAAiAAAA;099c̡ղ990:AAAA|AAAUǘUǘAAAAAAAAAf̣f͢AAAAAA$AAAAUǘUǘAAAAA"AAIAAAA;;AAAAAKAIAAAA@9qЩqЩ9@AAAAAHA$AAAAAA@<::<@AAAAAAA$AA|AAAAAAAAAAAAAAA}AAAAlAAAAAAAAAAAlAA2AYAdAdAYA3??(0` AAAAAAAAAAAAAALAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAA~A AAAAAAAAAAAAA?=;::;=?AAAAAAAAAAAAA0AAAAAAA@@JÒUǘvҬwҭUǘJÒ@@AAAAAAAA1AAPAAAAAA@:_ʞ_ʞ:@AAAAAAAOAAA/AAAAAA>AA>AAAAAAA1AAAAAAAAAAoШoϧAAAAAAAAAA AAAAA@<<@AAAAAA AAA~AAAAA<oϧVǙ@AAAPŕoϧ>AAAAAAAAAAA@A۾?AAADA@AAAAAAAAAA:JÑAAA?{ӯ:AAAAAAAAAA@`ʟf̢@AAAF_ʞ@AAAAAALAAAA@;AAA:@AAAAAKAAAAAJÒ9AAA@DŽJÒAAAAAAAAAAATǗٹ>AAAA:UǘAAAAAAAAAAA?vҬSƘAAAAAA]ʝwҭ?AAAAAAAAAA=EAAAAAAIÑ=AAAAAAAAAA;׵?AAAAAA@۽;AAAAAAAAAA:JÒAAAA?AA@Uǘ:AAAAAAAAAA:8AAABqЩ>AA7:AAAAAAAAAA;Uǘ?AA<|Ӱ9AA>bˡ;AAAAAAAAAA=:AAA8Wǚ@AA:=AAAAAAAAAA?uѬpШ?AA@\ɝٹ?AA?yҭvҬ?AAAAAAAAAAATǘLĒAAA@۽EAAALēUǘAAAAAAAAAAAJÒAAAAHOŔAAAAJÒAAAAAANAAAA@pШ@AAAWǙ|԰?AA@nϨ@AAAAALAAAAA@`ʟ?AAA=8AAA>_ʞ@AAAAAAAAAA:ڻ;AAA7PŖ?AA;׶:AAAAAA"AAAA@AnϨyӮ~Ա~Ա~ԱwҭyӮ~Ա~Ա~ԱzӮoШ>AAAAAAAAAAAAAAAAAAAAAAAA~AAAAA<AA>AAAAAAA0AAANAAAAAA@:`ʟ`ʟ:@AAAAAAAPAA0AAAAAAA@@JÒTǘuѬvҬTǗJÒ@@AAAAAAAA/AAAAAAAAAAAA?=;::;=?AAAAAAAAAAAAAA A~AAAAAAAAAAAAAAAAAAAAAAAAA~A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"AAAAAAAAAAAAAAAAAAAAAAANAAAAAAAAAAAAALAAAAAAAAAAAA??PNG  IHDR\rf IDATxyxW}?;FhmY9[6(qR $$^ʽ.^.s[\J -.@ dKĎc'ɶm$Θ,Y#iwު[0{48LO[{+@hǼ@%}(DLЀ p%g9S#6cZ,bRkwGu`+Аe' Gɱ{B@htb.3cMXZ ~ffB/`W%ND/8Gު!R`ykuke-Xp8ttA>H`v[{*j`Uk%Ђu~ oa'7I#p GL17wz Vu4pkgp8 H=8q]"SL[[j,Wuy(֮`/ S:b}铿u p3^XC愁.` 7sŶ֏;R:g^ Bp`80 ҷm+7g `x xJ0N=q`L|_5 -|d#0aumqq| a7WG20a_ V`}yl0 #@&u74ttͅiM1ۛރer.)9vpyF=]ֺ_9jvik78QQH}jVV_ϊ Ufk":KG.Npr`/^wq5=lWՄ mL~C$0EzAcR)SmZ^09Ɂ}sO B?fRM//&)$uUox*RU܌9ŇJw NgG8;*>wI&X V/nD.^Ʀwr+F\zޭT6G?v}AFOqS3vK"5ه,A,y20-ܽjѝT5;?'hT-e;mX6y G[ 9y+I6|r" Nyb8;EF;𺋰y*>)|'KϋĞ%qEmboj0"es=uF4_|hP*i?Rz1#BKI* : qqn0/6SĪPP֓*v|;~6t woܸMɔ;%R9׳*lS4m`G'qsÇy799@1PA(ՙpli:̭W|w<92q#b܂T .Uz-=6AIA-7+g)wc%67)p-[Aq@ு`ݩJ]@@Bq#B]I ۚw  &P`P 5|3lӥW#amݭl]r/66ABtoEZ}(}]1 iaI h3S_W~ʭlR*Om29 1`YƚA66V1*9(pS*6';BZ(龧ylqoMMVA6 -` @sy_Zov&CjXm@S9|uq.9I 7fur;qG)u&h*ߔHWw5r-%>H[q#ŠK p;iB>v$x.`VY0)5ps'x.M@C#aDy7 o|Sb.&%4Wl*6n?DPvwv0+H&P,/nu}Juz]EԖ1qS?NE8x'2æHP_NAژYT Qxn6 @ w/IEaWT 4W1@C#[w,ucERǝPP>\.`<2a%*57G0է:}#geu9̔lkJeekf󋳝o*W$wRS騈|>#"c34~ԏ!Tﭑ8Ԭ+j[j0#H{=/HP]?7.quŮWpv~[x0(5 J֠Ic(թ|~ǀ GHlfMeQʭ|]ssfe){NABT-W/eL(\kpiʚ 424e!Wr;r};tCDRM10v1.D XQu=63ƶݙ:pؙ` JHm]]+(p!:ȣx䷕tL$108K7\Ex3WOK͛U6V̀}Yd70lNfz,؊KLh]$$ou^> FvQQrb)͆MQ韪g!={yMX]fCϐ '34Mg'vKp GK~T\&=f'5;T2pL8[*8eTaSLH׭pR g,>&k/6tUh@r^gr VҞ-XE?0cԗHi5k.^~:=1c#č2UDsVR쭤EUV=c$"y`mXY}|RQȢRH%| :7?aXVUz躛 IuKKXKsS]P'Pm[љGJ?sťYZR_74ǩ9#d aRRPZfgƆUEieQw! h&sجPcQZL!k.v*c9B yL ~+y9+PYT.`m&?tYHgŤ`qJ}uJ. ~6-H"tfSvI~[lzXRQՍfR<#H+IybVռYYڛ0$o#:乇#]vHBP)g{} \MӹfIٮiko8nH.u dBO)[ܫJ&4hФ%Yꛯ{,+3\vi]w# \I M1rju "o[%s؜R쭤xd?FŒ9jVm,6@aiIc͋AH> &lݴnϺ9CX%0nZd#yK@Œq.Kpn0G{i݋\ƒ[l| p9NڇM(TPG1ߙJi%nH<h:h/{hN3s+gIAz.t Tq ުM,Er?JCJ_PCSRQrv!tϭ}tk䨴Œqs2L \4Uqo܃U(^>Vd) 4M'f;z|V/I"ԹjYQu}ǒԕpD^& e"tuy5e/]-u4h7wC<8^I٘ 3wKK2*LT#;p291g 4tJlX?,*]CJ `y7fH9tHJ@PRPCS9K.̓]{cOdĀpN̙ŲdS*>n`dL&@l M9R׿r"::KJie ey=T6F"f `rACZՎ]=wٟ $gcwuop:.ͫ0i) k ~4w s){Œr}J *CfuM j$ҽ΍L%xr`n0h(YU$enDP8ojp`. L[!b J},{knzG;y '%jVH*CAO$N@٫h~37X1ÑtᄂRl66NEDz#.݃[/§\LiJmgn.C0;E2k{޴|6e (KU[-s]gfƲT.XvE\%_a %Tɒ+)I* ǀlIf?@;2VlFխ{y fƳJl20)-tur Gl–{wr5>JIOVT_}>vPYں[ =B^}c}/&z>\p?v˄a JְRj48`#+77@#>! W"N&)9d#6*ds$՟&UEKiySr Dg BK#vqlü|8`3\k~@E IEQ#oSm$8`34Ml!X^y %ժq[Ĭ]u P.lҒ C+ ' [ شNKFUQ3L=FG.\W)tqU^#L"6/yjClU d`C+=G~o %{8L$'`潤iS^y3E4Wnp{):^ߜL'rnNAoZq  5;2je74Mc]ݭͰ%h/㝲[Ή-' 't !8!w1Wڢ~\hk0vIDATh,J_n|a0Iw Lln ' MVQSܪgƆ;Ta[\6P (w􏝒=d^P^X]% Sa2ANNfYr1]2tEsVÔ%8{*rv +|]!|{.V \6&DaC eJE~@܌r6ö"|޶HPk =l^P)r+~o0x>s7a;%_M~I2(lpӄ `EuͰ5X]#'#vNT3s$dS_ʭ=at]ThhăJ\`1^<]C+|-s}mseG^zn@Nq1K(-hbjlP||D7+97"4fJSy+m% 3ʛsms~IM%P #=+j-ئX77la8EhIS=xnec!+/6RÌz4;1cAu '{h3}kbP u} Mˮ&1qc͍8 XlM~\r֜D#P4b8aյ7SW IyR4whO;.!ҿ܃ @Ĥ)ш>,w<å/Yb;y1c}BwR;NŒrfe"ĺq'4G)$W2DSymMWl x4WluNCŒ9[g/tQlK5rDyGIA ˕]f57sJ~MӃdg ,(tp(MiDyi%K+*DEu41(K;0&J1$cQNqLC$N`"+.j:n>bqڏkRsIЉL)itt>N9l^p%C0W.zU/]C ~ R䚦3g Qb Kʯ:n>"W;C `E87a>ȼٟ1푾"N%RG4Mƭ䩶VrF 02å9;|qN©}t_¤eUK$: #f[_Vҝg$FT m[Ώa,>$=EtV TLL< Kpzp=m 8޷H|X!,ipz%Uο2- {5Mg$CG."qgpne18MXV΄N|Mߎ7-3]@l oC% (I)+lܷX&CLM02  MlGrT Kpr`/'v-KV_Pm#Sd$i΄]H>xżĂ|ïKw, WO]*# 3¾34yN@1S$ ĥN,93_A {YZ*'wZBǾ:8'la<J/s`ptRoURGCzRE''?@Ҏe ]ssvUN[p;9 DXRT5S]\y|7 BLWE4a.a9;tH;Ɂ=Jn?MWR˞?htϪg{2]a `5ޣJ\`_O)ȂSAbƸ_BOWd,DLaoMUVŸG4e `#=;T |DI>U57Rqj]׺oCEHd8$wP L5W|}hbO1aR)ڥ:n7vg%V /$;yd~"o^0'*i&njJZTjǒ>)es "=u08=xxq=r=y+0f, Mij64FN|[ 9pPI@t6H;_3)i"N|S Y#pbqH|c}/29z\dNi2WN塗LsF+Z]4)c<?}AUuS? BeҀ'\sACseNQiƜ<]E?T;'˼tɧR^~ $ \s%nDxshچ(6EѿcJJLapSK79c~h?V\WȂL]dL24M vqe =y=Bޢdl;qcT;* }, @Y|Y!z+M1yJ:`]ݭǵ;·u.l%HJ!@pj%^ZSfȓGEaw+μ4E2!Jy!{wHo2p.;[tE8C药rSM7SRK*B4p̡_x|PeO!s@(xH<]$ӥ{zuGU1:$ O`6y&+9M@=~3!kdϠ0C{?'q̏1 3*+eydܿҷ6yMN~T%3pQiw.,o`i!hʭR_Js&*&aYUs#knJ?;yN Qv3?0fɳKZ|KDb3o[ U2)1sL\q&~,x|G~3C/aOr02WOw7@yG,)@\I6b<>CK>ub\ L& }83ACC4Nу#\ïmߗ9C0# [BCt:^'9q#td2m7 )LaP6}  WtOB\!G;tQXt*tŹWc]]RFc/qb`'ۙA߹ mZ 37}e[U C][O:;ИxhǪ#Tg2Y~Ì\߻"HiA^Yk=ƮP)U_KH}%☿bS=t;{8WyL,1̏)Vq Q"R'?tg>ʶa:tMŒp'SS"3$b2T_aR{Nٓ#6++ڥtj2X {1YȎ|)NyOG7p/MDcW\N ~F9\ƍ/u=gb(rNu$PJ |/(G4Wl ؊=rd.W_,`ZUV fS_ŊY_6jA7v>Ƒv#U˔B*'?(pN$DnಝXCŶ"=y|[T>08$ϟG{!jCN@_M&նL~ojX* 6jA9 &}D<Pl򪥿mWaT*5*C!LJ}u,mMSfòc>K4Fa{nBeM.T)5j.̓loz%5͚$c_pדfÌ έ@ՆL6XՅm#p94MgM7O7/63C_cߙ4 3@h ۽D`V'ZFSԕpK˧h(]ڜ;M:^[ B~l()bnヵ nDhƆibɈ g]7_B\a_ q⧰+&waNu*!Lfʢ,)5KO^+Y+:g‰o0k>cxS0m6$dkq3BkKSz(H!ՍHi? Eҽuyq̄Q>>!O^4`j) f Ìuɽ躛͋{(p8DӜzΡW8=x^Wa^m0fGoTE">m6B$X\54d2\'٦ھ0.u G{ړyntݝQ`Odջ&ޥڦ\a a(/\DSU%,*]GOo^w0(!$ Äc}hh tpH>G@hfAŷiC_גv"uf_ϳT,(KvUwKXA=?5S,8HY my!>3gʂd7xȂJ,Z@ vX?ł8B0_?JvR#I&6p/+!^~ < Yq`v.X)~9d Ši0gO#S0Aہwؕaq1@h9 BPչ.~v9\5x:33 vJ@B2ǰҾPb{Gf!k>ܭдO{WҽΪ?3%:5[ƁcΤ=d Bf ܀O0ڀ s iğ;dM ہ8Y@;` !Imt8VZ5J O%*b:?78c& +h!s,'7Љ%Τ=(bw[{ X5花2cXG-/%L~kobexx6=DW#6a Aаڞ]Gk{\Z_*~c #sp0_r&}p\n Xb\^;^ a~)S B'ɺ1L֍6U9@hg9|$sppppppppppppK? IENDB`yubikey-neo-manager-1.4.0/resources/linux-fix-ccid-udev0000775000175000017500000000463612510771664023004 0ustar daindain00000000000000#!/usr/bin/python import re import subprocess import os DEVICES = [ ('0x1050', '0x0111', 'Yubico Yubikey NEO OTP+CCID'), ('0x1050', '0x0112', 'Yubico Yubikey NEO CCID'), ('0x1050', '0x0115', 'Yubico Yubikey NEO U2F+CCID'), ('0x1050', '0x0116', 'Yubico Yubikey NEO OTP+U2F+CCID'), ('0x1050', '0x0404', 'Yubico Yubikey 4 CCID'), ('0x1050', '0x0405', 'Yubico Yubikey 4 OTP+CCID'), ('0x1050', '0x0406', 'Yubico Yubikey 4 U2F+CCID'), ('0x1050', '0x0407', 'Yubico Yubikey 4 OTP+U2F+CCID') ] FNAME = "/etc/libccid_Info.plist" UDEV = """ ACTION!="add|change", GOTO="u2f_end" KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0402|0403|0406|0407|0410", TAG+="uaccess" LABEL="u2f_end" """ UDEV_FNAME = "/etc/udev/rules.d/70-u2f.rules" def add_device(dev, content): # Parsing XML with regexes, what a wonderful idea! names = re.search('ifdFriendlyName\s*(.*?)', content, re.DOTALL) if names.group(1).find('%s' % dev[2]) > 0: # Already added return content print "Adding: %s" % dev[2] pos = names.start(1) content = content[:pos] + '\n\t\t%s' % dev[2] + content[pos:] vids = re.search('ifdVendorID\s*(.*?)', content, re.DOTALL) pos = vids.start(1) content = content[:pos] + '\n\t\t%s' % dev[0] + content[pos:] pids = re.search('ifdProductID\s*(.*?)', content, re.DOTALL) pos = pids.start(1) content = content[:pos] + '\n\t\t%s' % dev[1] + content[pos:] return content def main(): # Patch libccid file: if os.path.isfile(FNAME): print "Updating %s..." % FNAME with open(FNAME, 'r') as f: content = f.read() for dev in DEVICES: content = add_device(dev, content) with open(FNAME, 'w') as f: f.write(content) print "Restarting PCSCD..." subprocess.call(['service', 'pcscd', 'restart']) else: print "libccid_Info.plist not found, skipping..." # Add Udev rule: if os.path.isfile(UDEV_FNAME): print "Udev rule: %s already exists, skipping..." % UDEV_FNAME else: print "Adding Udev rule for U2F..." with open(UDEV_FNAME, 'w') as f: f.write(UDEV) print "Done!" if __name__ == '__main__': main() yubikey-neo-manager-1.4.0/resources/neoman.xpm0000664000175000017500000000475012471132571021264 0ustar daindain00000000000000/* XPM */ static char * neoman_xpm[] = { "32 32 81 1", " c None", ". c #8CC041", "+ c #8BC040", "@ c #89BE3C", "# c #88BE3A", "$ c #8CC040", "% c #87BD39", "& c #A9D071", "* c #CCE3AA", "= c #E1EFCD", "- c #EEF6E2", "; c #E1EECE", "> c #CCE4AB", ", c #88BE3B", "' c #C1DD98", ") c #FAFDF7", "! c #FFFFFF", "~ c #FAFCF8", "{ c #C0DD97", "] c #98C755", "^ c #F3F8EA", "/ c #F2F8EA", "( c #A3CC66", "_ c #A2CD66", ": c #FBFDF8", "< c #F1F8E8", "[ c #F1F8E9", "} c #F8FBF4", "| c #FAFCF7", "1 c #F9FCF6", "2 c #82BA30", "3 c #A1CC63", "4 c #B2D580", "5 c #F6FAEF", "6 c #AED378", "7 c #86BD37", "8 c #8ABF3E", "9 c #AAD173", "0 c #C4DF9E", "a c #DAEBC2", "b c #8ABF3D", "c c #E0EECB", "d c #92C44B", "e c #94C44E", "f c #ACD276", "g c #92C34A", "h c #AAD072", "i c #E6F1D5", "j c #88BE39", "k c #C8E1A4", "l c #CCE3AB", "m c #F7FBF2", "n c #86BD38", "o c #B6D787", "p c #D5E8B9", "q c #8BBF3F", "r c #E1EFCE", "s c #8EC145", "t c #A7CF6E", "u c #AFD37B", "v c #EDF5E1", "w c #DCECC4", "x c #E3F0D1", "y c #96C551", "z c #E2EFCE", "A c #C0DC97", "B c #87BE39", "C c #FEFEFC", "D c #E2EFD0", "E c #B4D683", "F c #AAD073", "G c #E8F2D9", "H c #C0DD96", "I c #F6FAF0", "J c #9AC858", "K c #B8D98A", "L c #85BD36", "M c #84BC34", "N c #CFE5B0", "O c #98C756", "P c #FAFCF6", " ", " .......... ", " .............. ", " ......+@##@+...... ", " ....$%&*=--;>&%$.... ", " ....,')!!!!!!!!~{,.... ", " ....]^!!!!!!!!!!!!/].... ", " ....(!!!!!!!!!!!!!!!!_.... ", " ...]!!:<[[}!!!!|<[<|!!].... ", " ...,^!!12%%3!!!!4%%25!!^#... ", " ..$'!!!!6..75!!!8..9!!!!{$.. ", " ...%)!!!!=@.$0!!ab.@c!!!!:%... ", " ...&!!!!!!d..e!!f..g!!!!!!h... ", " ..+*!!!!!!0$.,i!j.+k!!!!!!l+.. ", " ..@=!!!!!!mn..opq.%:!!!!!!r@.. ", " ..#-!!!!!!!&..st..u!!!!!!!v#.. ", " ..#-!!!!!!!wb..+.,x!!!!!!!v#.. ", " ..@;!!!!!!!!s....y!!!!!!!!z@.. ", " ..+>!!!!!!!!A...ql!!!!!!!!l+.. ", " ...&!!!!!!!!^B..#C!!!!!!!!h... ", " ...%~!!!!!!!D@..E!!!!!!!!:%... ", " ..${!!!!!!!F..#G!!!!!!!!H$.. ", " ...,/!!!!!In..J!!!!!!!!/,... ", " ...]!!!!!KL7MN!!!!!!!!O.... ", " ...._!!!!PPPP!!!!!!!!_.... ", " ....]^!!!!!!!!!!!!/O.... ", " ....#{:!!!!!!!!:H,.... ", " ....$%hlrvvzlh%$.... ", " ......+@##@+...... ", " ................ ", " .......... ", " "}; yubikey-neo-manager-1.4.0/resources/neoman.desktop0000664000175000017500000000037212511241171022115 0ustar daindain00000000000000[Desktop Entry] Name=YubiKey NEO Manager GenericName=YubiKey NEO Manager Comment=Graphical interface YubiKey NEO management Exec=neoman Icon=neoman StartupNotify=false Terminal=false Type=Application Categories=Utility; Keywords=YubiKey;NEO;Manager; yubikey-neo-manager-1.4.0/resources/yubikey-neo-manager.icns0000644000175000017500000011664212237161707024014 0ustar daindain00000000000000icnsic08 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP Y߂XSqJfu)+1dL!簷*UM_jȩz kj~]>abo?9pUSɢw1ܻ߂8SqJf_iոP%æ/\w*Bɀq! ˖4RlwhE߂PSqJfХصΫ^5ȲG-WQow b8&WqU$+iVy#k+Paٙ1FHᴏ߂0(W+'BZYM _/_˖A@N̂xMNhoj ˕[o~ 7ssq\+@ކI;S Ki<8Vo!*%'Obl(7H|s2-HM"qCr-}촕ۀz<+-I{j{?"yQ0q ,En0CIhcS^]UQǢ$ZҫzVYC!1HL%s~q 6|R_lʮ~ A@>ͨ'yOog_ ~P@Y3LȲjvr_ਇixEffеWA5U*16$ xW;cD΂f[7zTY֛3Ol)_q`iF=-j:ԠFP|τȃEr{D>"(H?qV(Scv*z2+Tw}i#F.Q y`RO-7' |IKdCjyѥʫ9ua͟Ҋ6)U> O*mn 9D\8'yZS:>B'\ 6M żh*M hՁK 8IH9+T"tYa9Z6RM65MU`AH M2} w ؛)nlwr0,5N ՟dui\p2NX`&z %ll.qR4ZV,^ (\OXb@Z+*T^g-|`*#]ܻh"4m+пKK6k.)ag6@*{ ˃%`Z@UECԇ[je@z9L,d=ɔjfK=yY@iý~1Jm%VswyID;YyiVN' 0mڕosW,jhJIfl+u]K"j!9/9]%caP3Gx]Np>>=<^v:,W@[ΗFwKQe,L5 V.#?\np~הK@7*73bU#'8>-U_3TI4sA"TN-aQ si*[+rs8߾!3>M)?DZ8jE؆C͡aZg,wp$bx5#Y6k)2N JBީOؚF2g MyջgJ{ڇ8烕;uK>Ng֣8)KTM3! /#GʖFmݟ:ˣOf2Y4L8 `˂;<~I!DI5mfBӆ#BH~*X$ZpӞ~<bǥ mGZt!kfb[΍̸+W % +L;Dž1VQ?xTT} 賤$YnvVዣ hh-~5,(Z~E|ÕLi˴7f+вKFx[kMqq8b̢~3/޿ksTk80cjDrw'yhnld1+Ir&v2|ZtM>,FCéc:ηK|AUb86e$32hWt|,U  쿚f?Mm}zyeqW%ȁсmEW۰JWq4@ *ێӉmào>JH] 9oe>?-w4&0^fVrfI ߋy Uc[?;pm,~~Bخ:VȨegSś;u45=+Lz 0(e!ۮܑTy%&*YiW E8:z[{(3LCm^teVͮ%96Vn >[,6O/SYDTT0iB 7nPj!5Z8炆rU :#_`W=?˝aW(Q[*=M%95ynd‹I03?KJu9XtdEi&FEX m<[[Z`јާ4 >&)0l!OIV9}RvNTtK14+"gώNvA7O?>nfSzXq=^gk?[ּ<~S#U]ٜwɯNH!T&d>Wɖ10&V:ciY(#'%^,0xtf I%i=wSV %?t#>vO4#1nl}"46%d)>D~3xm,T<.? lPԺܵ;-hn.J=(wz'FuEꐙi$i-K[s`k!u|`l4N!_ǏP>~ϳݵB`{"ۈJ젠˕/Ms"abKce u][K#"x*K?V*FLP /S?.0r %v|"|,UJ n"!7eUM>dUuEԌi  X=zϸ-h ѱ)p$!\ b՘-VE;σYtDNo&B(H0rw4H VN.i'~$[ڙY0P׼qJZ( |zb#G Fg~r =SϊUuL&D'vy sA  [*2AT!hxjy"vI nJgb{`6zouKdžh tŭw‚܉_Z^Z)oEay:N\Zxt:@!1hZ^cGdXa# Bε9GuC'@A SIEX?,:V,kY P%)IvFY?àt @V< |qe 'ژ;˘#T6i3)dԴ$2wf](K*%"D,(BuI<+0iyKÍXwmuS: " &08 eqD:RQ̬FdM4~{GuJ`^SҚ6}Ėwܤrvi2xG+~8ډ5}^&}DBFy \Iub@`JV aa`% `Œ)}`.' E^ҁ fjͻ{Af L_l ܤpjid4QuPp#=gxk{3Ec7 IAчjBcuZlώo&uGfVG@^! #v|/y[c)$3t(sP3R+rCn_ w-l,іb3 a47Vgi B۸e?>]_3#{,WoJS~due>9,OѨÓĻ(ʔ]~ZR-i._mȗBЩK8wotC-3Pyi !XB&մ۽_m B.t &cI%$`Qn@gr|LBJ< 2Q\!pYh33vմm ]!S-ujS3GѮs\8"ONf"6XmM<ZgwK/q֙yModx #[HIH) ߛel!k$=7L0#҈0rUd1rmBVp4oPpa_t0P8JA_tҋZElg҈\&:~:6>$'̆dfn.yJ-zsM%Kk3HO2HRj۝"{ry-I6apDΫI1ƠDeY4SEHHJA.%džaEYUֿ5gYUi"Ϟ7hb&\*O0ɄobPւ#u_<7ڛe3B9deۚTf>XԮ{AA`ӽ`~2L4!Wel |}} k^uZw^9-Fk/33Cz&&k&hr.׭Xݯ/3Dbֵ王/) ӭI @d)P|'d8Q~o EAtП/ߝ~z̀N!~E|8= >W9îw`f<C% HHhl1JY`5p)C'!5]ƉDrLLcfx=8ve2AeUf}g/2QBz,O;ftM(}s7S4;ETn0V;> zQuګ5 7@w+tYEֹًP#Gq4|1=(cqyt-%HgSx!,zH k^Ui>Y"qa-Kd'OtGP3uwA޳bqI%>/9`@6>~ pC3@2 ktm)IGIѰ,x2t YRvc48';mt8hB=_c_{]!K|S^`I??IsÿStTM CZ>|onkHWAmG4;hnm⅄#iP+s.Ӓ5Mitt%YYNW탿z6V ?ˉ$g_۶rxFWq`dy_ztT i]VkĚk_>~"Wفvl WRc-FZo˔noQql\#ŝoDVf:CR'@O3Ounm,!3ĕlrmhйgol~`RE# 8[*I<ņ |i ] xӝ͇o2wDߚ ^d%*ꃿï_&<~)慸Zgk8;EDn,ic ,Q[ta$Q_/ >\$"-L7.88PASa HZYG&.x` ^Eh\2&~9ԷUk = jrr}$D﯈,4DSr:0^ {@ye@|c5\}^!Õ8)=qϒ4*kF=sGD,S*m#GHTlfWU'AmZE6dݽͷ/LmH,#^g!nZNC1኷>@6X9arUQ;Đ3+<ԺI &K+s>mdJz1{AylMٱ 2!YĦTGӫ!,F}\m6̶e_MkV]i+)KfSzaSxxܛlñadM ?cT?!GvΆ & ՉvJQmkwJLJ5)2`8mig`OVЋWyS/Hp؁wsT9+Pڎ8Go]*WT`{,'p`SgV7vZs m_V@'fMEbLӍtvp58ɿIGOnGՋy˼&`8XAA#~#By nC,}D FQ~,ҩq-3LhEaǐ}Y9ᒷE6hZRt ,7e+zi,zcN,/R,3XA|(f8V 35!=HS2첉Xp^顃|J_5<%?bSIRu 0o x{y6N)oFm$+KQ{ r0E _:W MRڟy&p dP8 (fj@R|c҄h䆟a0R *iw٠V۪`pJGIEq@B<b/U2R+vK^I)k6huP[k`y32ZCߒ  ]O{mi?@W>wxη|3!\gG=EQ\G ._rCNTLƿ^dVNz=}W; >5H$ 5eZF b V#HOrGZEړOW`U@7FK"% 7r/AS86:T^mܞnLϴAِ)Raj#6I6Iǣs_ѺViMg@q#`bHn81q q64󌆑M϶aV,w<RM=DnV'NUچ9Q4nF4@+fxz_Άځr[{ O[9lCeMҹ-ށQ܌ډԆ i<\;TMU{eMor!Lj-J5@џ́=c(4a8TPW-R7s$8qZOd !c6aH+OP`v;sW)!UfKMqY1vQ }#wmD d^P!7@q`NJr:6Ay}u#'&)lʬ>;QP'%af:8qIb?QyBzA_]݂nEVg {𴫶)ݚ\N{nj~:h7khk8xkOҡv|vW`)=:N"M!9ix+߁=xu SX)uګ? nDg(!I&^۸-"{øZV|S%8PkCNQ}˜e gWeE0"}N6 )x(wƘ, FI`6s;{<օRб/[H.\q)֛OhՆTIw 3;AIv+-%^cq`{1{G1eSsAeAI9R8icJR ? u36m\흃(ST/}Q[uS`rO[=ht `rы;X3;\.p$䯷N86i[m٬'S}bH~Q<У\>]+ǏAj@5M!vYɊ >1%)j~ rz Œ5o4~,2TݚW+N֤p(u[iٯHh;ovaH%OӬ.XDХ(AqdAo=å.ci₮ M5no5d_i[w 9ejǂ7Iѿ~ Bީ XnZW=&}M9F8Os%-+|>Z0Nr@K\ZAqKcf*߁P[pqP)zifH‡ZydH{C.V;hTz [%IɦY's}rUd _y,eE[{#%6'Y,f7hj2)YYMїJ\͠1G`Y_I/ z2`]oח|?(c{Exbm|~VI?X= *ڼ -ۛ7NGIhq9M`@6klβdY405p_d*ak.N9 E^Pr`>u9аo4s[`M,N+O8)C6$m'AZ:kc䶿ݽl}c",MW P^2"PdV_YU f)Z!c1]y~I\ aJ,FKF ssQ:?踃3𖐵vm#EhvO{SD4  oI-< |fl24u8YSD-{ie2./` w=U0¡^PʓZ> sV nERBTonw)4_U?1He8:Q&SWy5P=I=)PŽ A ezv1e=663{qv!_Ə/x ,ƄTw'ďfsDD&ϼM]&zGe"᧏ |O-Q)ӓZx"'%AH^X_t%kP?{2&eN|_uHƜBčmw-FqGX4gO\gQ]%z*Yv/Q$A=TO2ƤE MJOf\5"dð #3e7k@j&*8eWhAUӴw=} ޠ^ޒ `P-?{꥙J/Um, Pc_;Q/Yx 4h_?YgAfn=|]J"C_wjJv \gMPG &ম=+S,U4cU,y`T5[8y%'MAYEH]“ 5 qzѦ~Ք:} }P19q?ͽoIB1_Fmy I?E.k3 B>b1J0;zflk}UOu&d_WQ&>m6AMCZY楛lӶ-EyjS,>ةcrZ>uh,|?E?E!~Yhs4=ј1͐: N ڍW%YnS%noXa} /N9e_\gN֧;u0ⶊ2z VE ?y֝4S UTx 7E9&E8 6?ZQ(NT"PLJw/{lHIHn!psd屓FxXٲ^q x̓"xP*]z FEW&Xq6 z&_%r*x#v\ԝclWQWD/(Ipu5ܵDY ِckN4["ƻ P* {Hsx6M[2QI#x4YX RO_q]= }!d|Ԃ340'brwL6-D` nIh=Aa`ŗkވC"?FeyZ𭊟EGEFz8!ð[! WJ:9YR_hFӰfMY9l4 nDp(sհj!bv&l Dte˰*`VqUCGWe3ZzLA )C*&/r0ЮIN,v.?F4Zc^c E(EUN͠RtI@I+d4xPv=xLͱ'3@Cҽi֩\e/i@aIĜ+1V0 hCwҌ0YC0&(9Fm[r ^m#πvm8-DHagkS'&r_XcE2VC}wYr@!n)m]vT\YBd^7ۍ/[:֘/V)6 p_Z m=Oz.%x#˩/'ӎ{KsZ I8+/Y}/_,r񽎱u+H O"AL57TE%oGsꗲȂhDIFiЙ[&_DSFw^mAMXE(%jԘ!ص׹WSU"4վ4ZT(RI{O]1f^d/'zIdap nT[RNo< r'Y6àG'::skǐ {"ƯKv0Hۀ~Uab`~[rvc ~W13?9VP3a<Չ ƒ@;1Qb%baS|Kڊ5ԶNЬUE#o' X`s3c,{ptcĆx>2wɓ*de' `kϓ?6eհWBY2:"+w1毐>բ62QHxGSA6+ (|4+TeӰ{Loui2HgXTa΁0IoNVm冔Y,>ݛN21yg@cv>EF9W9"ǼD.ǴRPgіK3ѾH2G(Kv"^MDgߦpң^ӳ&bT3eX6cƣPV_ =i1_ξo^4T_(pl}tY*!+;9=: `$njq.D`:pc)6a#:E .oհdobG)$50a`xxc͘f~_ ˓h6LF} s k49qwќ&-X|`$Nn9KODb+HQ, $n'O: ߳Ro\\sȷ-}S{mаAF>K3Q-2cy'2Ӆšr7ᵳ j =e2x,5g|1wCJ5ۯ㶂wYy̓P;BTqy%52f)O:6yԣj>:vB^e-@úZ4Sg]+C4졯Taԗ$HCǙL>&B,x8mȑ!r;'xC؊1?>+Jx;6'gBӌ <. M2t4=H7f,OTƂ7n|ŤH%X؋}<&ˡk!t:҄D?>Bb /O.x 3IBH[ ǀsAs- VF[NU1̨ @%uO NOgl?Hŋ"YP JlzW z8 3wF 6,zKz,U00N2i_ ~aG$[ILa;V檦F~^D`hl"$q-YR/{AcjOl:ۛ,)&>.z !xC>W/bD?{!b~@&hĽ{= ratH?,TJ ĮB_ҧ:W?B[D^G+3!SnOW?.pBj4[LUҋoR};Cd?Ct|&uiM wINwi$HL'y'jj~WOh*~<X`Q=R 4 4⛾VnѺoNX.T')*kWd1cmB)F0Q=""^W!d p "0YPcàt!юq&.@B$3oެ.L4V:p#X(kٍ2SunRR?,M*qV-݀g-¸WP6zNc2<5x7g*٘de2=HGGD}p ҅?YH5#9>ai`OSAAM7k.D+Wׇ7Ե-- )yhNRs+up\5]K9" 3:hx7kG؇mhHT5=[oe:Ց{'e3!dssF8s*#*8oꝦ&~E/+ln02Mԥ{Ëk=gL }jm:IF;N)9,HF˔4 @&Cn?jm2a~ '؆ڱЙXn6}b0,]fq!,wB}t1 ~7 \)%jagL[mzŲH ]/s⬒7v֛FufO׊rˑ?p?cIG`B0ސUM%=T,72_M{%KM>꾦*$s׽tnpλ:bX8g8 ("ٔ$~b.ϰ+5Ӫ~!%SiE-ID%!H y*ubqK3a0.3 AUE}-GX=(zA wXyQ8Q( !VaJpGrgm?I9XZЏsSgZzgWCJ(oP2E'bOHBzō]%Cχ,yeeL+λM |N]`nF! GfDxaQ >@IRVO)SBHaf+ ^C*<;~-NqtE>? G:tڈ, S6eBxH1ST,Y{azpg( rC%'ZNz.O'k[Z?&С5\=fH_^,9s"9BC;УJVf@>E_Xn,Z~xaSa>t*%>*x?M2q@J٧8ݦ (t}J(TuNJ*[B/.{R!1rcF􂁮#ԌRosg`/HwDp\5bd_Nl}gm,iT +жFVeoHmX܋a!j+3.(AmD$ܠܤs<X?BwZwLޠYd>x@Tifl|fScxENsSHހeN@&(Q EQEE?E:-7/_xt7wC{߀D6L+v5b^W|e{$lGth7XZGÀd_uY\3Ԥ#9gI:̜O%%ej |(F 5`]~,_: Dzbi)8 %Y6] c}_AU+R2G;3# LݏNQyNf z2oS6_ 3KS4maJPTidŽ~89J` Ϝ6gy -|,]kifŋ￀`seP|Of+yDX߶͙^ML;uRfQ?AKa#@no^/;,[;3`#r :nX}^H.K$LPk%/HϮ,m#؝U24} ^ZQ㶡D:(;"3ѿX`Cv1*|XLO&2_٧&V!0\̴XVz0,QSػѫG.Ib\I_Ч'q!2&;2֫ ;yYA*un!睤~yT{h]ҕ MvPo '9#gr!y.u>ƝC'bkp{Gx|."]AVʜz$+X^l%\s7M刯2UN%DɢLM<"gz/n8yL{#/~Ss7[bϹlb黇Vu~5EDnIS>$+5lԇf ;Uh|#wQԬg dom ^aM.kàRvT ~1Ѿ"M@ijXz_)~qQdg NC< YZ>Yv*<$ 2fB ΁4Q?y҂'~rb,W$;ˮje>z$2nнyvB;vry*$9T1K/ǖA\mȹ|m/*ʚp0jq ƃ㙠>/k|ʢy~4>-օ'@lQ{N6=%S+(ǟɀڌpZ˂"9HC}(@jόwfa JlRCTv'1hz$rbʃVIc3{Dͳ'#"򼏰}]yA"pIp"R)8"3h mgcx>S$etS9o_"<A/Yc@< AO܊4s4@f7AŮ5pl6(pk25?exEI(]3PN1@~&@"'A7B/BEiy3?AroFm[ I OicBPӟ 5baW'`  p>87 ?'ͥ N㱄 )x j_K $u7C}pQ5`^!ݟZٮ96y%D 0[>a1~hjEQ Hڡ(NP7+\VZD\tʈ2Z ff6|:Q-㙏^s.Aȕb#Qs2<*@sr808Z:@n\g7\>muZx&H[fU}iL+g,/SE$ݮ8q8e8{p9bcn 4e3ڄJVf9>W+lXJo`z8pjYn~!M([ĉcGs: i{1?x 9-oJZMLlLVV42Mo:ÑF|ϋw K xFꙛL:_B$f *4<״}GmU֘_ڶo{&ZǧĀe6NMk*KްΎ .C%K6/<67tn!1dzʦ>Ko-{ r6s׫N>":y4mcS`B><_dfJKPy]ZߝgZq7gN‚77e 8('2R;K2/G\NhJ3܃?pz:.|N HyZz3vI[^o\Al;nHXahi[۾$UQnC^C9XlgE@B̦p? r# ^S^ E˞DMe['o&rz+خteqUXG&)|j>~/Tc#q\V_-x$ rFǶM~?+%*<#*є/ zCַ͟?Nt#Hk-HeU_Ud8@k=w=%c?5LCv&gЇz29U`gALj ߢ,Q@T *ጇ{=+$cAlnA Y 7',p̟Iԃ&q ==Q=+]74<%^ikg 7nsNW:ۨ{gp4mEf[ 13+ ,Q?ê7ܳ|KkZ \VӖÚɈFCs-'Ru!$f _R<OhiĘM ڲ y 73*X$( 4 s/J=9.neJJS5%f뀧ۢA|*SQi5ޚS|OуC0+t먾0& UԮ$ %kE|ټDBk׭2x?ߜ(oeUDLT-->;YD'1]mM=s(؀6yX L.җ'oWK< h!s?|z]uv3)IZ W}=qpZS0vYS~Pw02^,$YK=r4=iwFdnbhd?qtBLզ%bi^¾rL+Mt豉Oh I c_qd:$y x5Au6~_:k~KWf8ݤ:(ÄEp*ZgB;ftQ2GgDr*Y')k Y]pU%j-`1Hm%KI.K-dy޽H8NG&oP^Q~rݤDbRT h!˔"N$aKH jWmؽm1 U\:W3Q ē럫)_ <̝:WnM])+d.!?^fr#$$h !;lJJB0 aD,XjWq(a3}lk\6z% e_8XgDᳯL@1#Mi߾7֠ԝS٫TttioY83qNMhNd!rXHZQLX\]VKQUSY%M1S9K[YbO4,FzS{؊<+!Cb.`m&$_dVgcEJ6m5N:>=5P IUөVa (d9=R6V@i^mèug5yXmeT= lt!c/P=SZnAʂ$a sqT鞙nfl ߘX]L=(LB A:(מ$zvMys"4`8DW~t ¨Zշ#J!T+LJmqMK'],3p# [U=g ?L({Qe{5(s\J!,&R ]NE۷͆4?W"(/5CK='_gDqm/~z5Eqm (63t݉\)F-meG>_mޗ&K&tn!L*?88͈Guީ uK_c!̥Eʿ50_,q7;q2]/ dw\8[`/J+6<\w1mpW/ld ,~Cx̔q ^Z@J0FL1f4ݰ$oDMÞ@P("<%$_gmp7"M?+t w)C6,FvDah| [=UEwƙRnpF>% I'mp/n^7r Y/.g Hz&4]:i#7ȯ:䘊6{a&%It@f:N"Kݔk$Q?:J&{F"I<| ^*(/fd]nۇ#WlU M|c]=7AJ>KjaO1&RK#zP]6[?P=V cF1q *1PJXc 9C%rTroyo[.)eu4.ȅ&H<7`iCVҸhV9l &g6⢭:ic i`I)c&ƢAq,PB=A )q\bXrޯ὿s]O\_5:Hgh SHe[LTKSǡVfmIyV' - etg9"Rïy%xr}D# Z%r?+z)Qa3z9{0bJo%h S#^3ӫ!ZM-Xsbn2B !6YÔaz8hh,/Q./JtWTz5Ǫu=^Դ&=w*Um(lAD3I\]P{ꕅܪ !ؐ1rˏ:)XT(q?uM)sWƍEB\-gpnQ~ p1) DCFͶV<=@NpG4>*0;&f%fڕ,8=Qa 4>W/Rh~/5gNp6$FIi.H751 gS;*eN&Hu9+]A=CzwN+F0uR"ʍ`0v|jNMc m,3x u>Q,"Ik~MJx2g0 PX?`Df縏kWꓶڷBtb6{=:a5!57!{oSȻ&-cJy'Jqd0(PPEU Tch&^r Nv}*ՅF( ߔzPs]/d~O&k.n/Xz+JY*@8p׻.(Cc~"#wD->" 0p S0HSʪ Z^]CYixTMSjE Ko˴6z?:E:*ڜ7 44d:n(*T\Qç[mcC#j{GMMu:E G<ږ_XA/-xz/onM7I`c dMi)MMeNW3uQz୴+D?w˱|N7o(RjT9DTqcWTkR?2ve+bEFIelt!K22`]n-hދ] rߺ=6 e *h/P<ޟ#0{r@ >x= ay?0X5e\>pWh?7}(B}cҴ"pGY+MGӿLe~Ցq$8NL֪1p$C#<$tc'H7Zo4) Yr)g"#{F,3}'\m=̔_$/O[Q^x 82J'F>Wܟd{ z04<|\/5ԃ+|=Ckj[xLIJ`+ ª-~In{TZHxD M;$x]2fU*{mJI'̤?J18!ktSp5͂a*e;)_[)y{Dfk4g.&Eg9_]u !oEnVeDA.EJ1&[zVC;}CmmєMҎ (5BkT(lRFT_zU4XoH,Qh!<T_bk6`θeBԛ#4&af+c]3aݑG}O|xN?lI}"zR |'jn fo_T"վhZ22]0'm)B4Q(C /Ő?a_O߯Q0S(+@2ɋȳNoj׳ *e+gHT#>3ɶ,Yo1|+r#ok@¹AɥJGF@iRx4F51[Pe.^G=)[+Kcuf{p!2~sZS>4>m UH'F.Yjr Mq~#pcyˮ989Zg^׼[nOHPW&kٺ|:k5¦(S$ S> S`"9Wd C#B #boã\_EAxOq> [%K ئL ?кn}CN$&Ⰷa:^|tICwjjY4FX{zDAi{Q"=>il فgEi#`?p 2-6U hNeF\\D y2 aydܗ#ѯwb,qw|qLNJrBnR R  #St4_x/; M{/"A;b>žęJM7mza5sћ }<ԩ3CA:YAnPžMKjIGm$wz )Vך Ω|&;;c3c Pޏ (0&7^ ݧvQRH%WFv-}ڳ:{{;*y;W5 $.<4P'Z7quM}/Eҹ2<(-h1-];/f 1h2 #t>LF0. HyzI!!8:[;B_ػ%"^aΝ[]?}9B8/2*;.fmIUu6G1Xi wc^[W-L (G_)]DQ@TEJG#|nTdnȤwt,@^a{V2a:{%++z;XwI9t=j2eUd Zb%H  {n>z0(T3dT! E.a#OȃE{nZ%DOh& 7z"w?ї?ۻ~v8 hm,Hd;G]}*,u B!ûmlZ<@ h㘦r;U[`d_O@S.O>nߣ{ Ej]Yk`Hh?(tk5jZ8"AJFBI$ OQjj\s\hY'_rߴCiWA&/^y'!,%GKA/nd_&Nv"&(q([NxK89ÇXgP25[Vlt8TJm5Л}tLM2Ӂǵv9Saf$'Ʊ?\|3N@qczV ŠBK] y&씲osͿ1#әw<0xZ/Z.?O~m_F.88m}l4 ^iPs\: F.=\7t܄D>mîlq7*=4>K]~u[+Ky~جW|9b[* Wc]R IcY`3*fQ2yĵ`RB w3VxUzRT/ dPĨ5[`Va.%pό /8M"˼sZ rdnrP~6[)+V-8,jUXw4ƀ̯':B@,қfln(#c3v8 rt,<;YFДTZ4JHUMsBKYa#jԥF>㶍Z,߫B{OWvE;^3m ?u"Lȕ=Ǟ8 M]m)їFz.I3[[3Sg:|I %ݪ?Hi+_ XLsZt?i1$]T|O#ة[Ky^T< 8E_*7|2OGqsw$ h=Ra.*u&Y皭lGҖF)pF2h=E 7x/lр$1_N-)BҮ;Q{Ba`xz.`)9@>Z9Em!?_u@ʀwroMupKև4,9^ jXi1+D.vek0#ۼwS@xe0jBU&&NY"赉- _BB*g]&k_6GsX><]m 0i0FtfB%a3|)mM"F_}oPfj8bZE~:[lL<)%۸`gt4ay$jC*O%[_R*|h0@;GE#2Yu!jao;.t;{:#0~vB Կ8YGh!摤Z}n$G0xt";@{϶,s]'* :jt/DK*,ʧDƝZaQ)<k+hPA0V5p?S SOwdUw. p#f:z=|^A[\DsnX1vUեx,vSQx&=Y7m#+VIzRC?7=>oQe pܢHo}xil Q0]vxOXm9+My ^z"aqf_ПUYqYrҒ>VH zGUTuӳ.O3eG\9x17Iwj+4t޸5`S AkJ|ߝ 3(U*/( p,|œD.u#A+2TRMdE瀉HXHufñS@PnlMi\#>M2ljp5Ȣr]_G7!2khh5EntZ"]XͼAMEw8rФ"U1cM*ֽ-\L~Ϧn! FP;(,Έ#itcW:ުƠ C;\>lbɁ ->dT]o_~ŗR?GY-h 0]̣?>KXCz%= is75zja2'O:7@@?9v`mO8?M ߩ!tW+Ri;{bẩ{@ I-ʣW?DL+F+ܖj0'-lr@\|!M <~)G5`k<MՏ.vnpkZ?-77QwPiS(?<)볒3sq~<,e4i1_S}V. OŌxM~֘+<ŞAHGaF7S+4ns~_^?Az'ԇcIֳwf%`] ! <7N+k}ѴU snחdedy"T{HHi,ua~evzM7P_tB΀AS5Tϯ+]utW`pcPc`ݞ_Lz]KT"}^DH0@->d>:q%V = tQS`8/Fco1xɢ{PY3Odd$zf~+Q 6}f#Wre>0I4`IT !\-n;Iqq#.Zv{sit؇>J2ƕ(R`>sR{?OjїXH{`0z6ܺV% b5g_#> F(܁C8-dcilꁏs#!QKUw05lG4J.lv{QQYu>TFq^!ro!v5._Ձ0*% ^pn)>ۦ9_*Ϫ "wXƗ&{zU ^GjN$$|f̰GAV-m;ar]uzBGaJ)`Y~[ ׎j_d#_$Xq')- ߙMODΣ:~mXΊ p'JYB=;Yrڗ 06C~U_K[B 0+`AAhh0%I*9Jb)l24 hu><QϜWƅCR~7o_mC1^ ++dJTjhKVwB{}^& YȺ52W B vQ95^XD[?Z1#+"F$/X!K9 Zip BZٕ3A Mqˍڑb4miC 9|ldۙgd.cVSq0 VFى;Bg߷AV3pM+C{(̇`qBH9%3#39LVΜﭖl%|oB͜nJBW̞6E㼙6C<~5m$BZ獛VPnB468u[S$k0_X֬0dʧ-V M9%+E5/!1D}pjfUzGRnuDzzʴI1ưp[`t+AY袚 @~-BʑBVTWL )‚r.%ǜ֪*?' fx7ׇ~6sۨj|%@zEM~s`!'4$'J~\_awm}v_m}/оCZ9s{  V/1vѾa[Ўh VӺK?&r ZCDm+VLŤE-K3]g-SUIOb(si.mM&&wi$_0mZ/8FP3+LzsFӺnͭ\6tVЉXu֊[Lag\u2ߝPsQ*4jxTB#3-ThS0M/1jA۷lE[ VDR:Ͼ2)MdP $<ݓ;|6Cdcw /˂3\')dB@PY*X-~}g J- .3?j R!nM$KipD8tx1 qJ&,m"S7xT@snkndt$8W_TOc,n"P B0MMvUapd -2\ (B:D2E/}e? O1rjygU85s(% W`bv G?^*>ݲ܁K/Rp8xēa`M}%eoi5Ns'Y9w3-jG-~ø3=UaCfwNru97e#|lFĂn<_ y P=) z PCז]_n.⥗遂_,5kV:h R)zTǀ,3xc~>Kf=L#!x 0ee*HU⏃ss=/iׅ͢s',K`$%->)2\˳NtsOHJ +!o%6Wr 0 O}_k\-RDk)v ǬfZщrqIL* +f p6VI'& &Dy)(w9b%C.rI{睌n RX+6Rh"m(ؗk:"p`a5^þ)::GDu7'e[q{󢣧[;%٩8c`Lͫb ֭ivU>X% b6c1Ӓr:0qD2z بW$m">c/؝/GJ|_'PrQm'.l1S9fVwV|͐'zXgwmt0?%iSW\ BB3l$V@vƾ:|i9犊%72n4}.P Yt_].;u$D2fpr`@ ~ uXdCU353oeƕUZ,ѵ :Ɖ^ ew3bGSM/aEQb[T)V'̵61UU^Ÿ|lYq8=Dq/S#`9L(&;m]tJ)]2U(+%q)3^>RTȚOfhcz?3%fC aW"Ugu<  CRm}61un;>ֈUK5L_TcE(!j.T&Nt(B|k;VRdHfZw?,dfW=[=TQ>%h:ç[l} h Q!c FAQMT2ӍX 7e?j,,볹 k- ѕu8%k]"'M{2ב޴snS0_R. L< ~ap d*FwO/Z9%`zRnax($xnBȹ~Esɿ_3n>ۇ: 66"/+hl,zB04b۶yr*PNe׭u1՝awc- u<'g('YAS}^dYު^.qPFѿ02&0Ϋ(}@r:Ydݫ"R2U?]&\PÍi)U:";"hty9D=rPTJ[]H5Yڄbs'7&IiΤLꨰ"prץ˹_oЮagyubikey-neo-manager-1.4.0/resources/yubikey-neo-manager.png0000664000175000017500000001400112471132571023625 0ustar daindain00000000000000PNG  IHDR>abKGD pHYs.#.#x?vtIME  !1}IDATxgp\uv ;EXDU{!*ȑ#YXJ,kb%;KH'3eDZc'A S"(AX,X.{`@$-(}{ι1[4Ӿդ<5ۛcGN@#P"]; AI\BF@,pk2=2!dRD=no|0e G} a[$zBvY-O?n+"L|_&4y,x3P l2RVVx8 yEM`<XuYG4y6WulxhEA|CjXw{4[jG,,vyގE&p'v6^5osahr eu_"2 ^𸽇-[^xټ"@sk 2Cg56i2LdAW#y KNLnr=F ΂XDd*q8Dp<D *Ba-+K/k?Õ%N؀ Eٶ37H, KeyMj,O5c%f)cGQ҆\{h4 O !MBu&*W 2F9E IqN'axSGv&R"mYiYK;{=%Ha18Csjxgt FOn ZM|[i[&{ s6#+֣,±G^WD^ɈPr Ի6^R-(U` 0*WRf]yRڈC^a`YtZ=WV~%E*46եEik>kTW 㡨cûU!ޗ./BsP[M`;`HZiib ¸>Jnij~SCQzR*+Ӷfjэ5w+}76Dy9 6ܩxKlږ NR> hHAZ#Kn@d*E*5' `G#jpDDĤO2pd`ઝWb+,5Js%@ 2ږRڨZ ߒ-Zƒzڅ0tĶDmhs=uΫmȚ[6\r[<庆\6P\/|P2>J,#+LU2G.K5ʶ*8f(JVd̆5R`*j;ۿ_lR]QVL->u)18c,U»I"i a|rHUTW>4]h%inmnVȵwoYѳԝ5bE IMBֿyU[k 0 GȫF!sk#fLaUY&X0hv WPXq(SV |6>y! / !5VmE0'NoO ML0PS UN˛[@Z`mE.[ʶbYvnN?7{JlK)\GQj[BUd>ѵdV:VIh&BI$/L%8{GHږf?()`)t\QMx v3vsdE(kf,hsVƠT,OaCVεI4:Eo{/DDh/)l`\\?:Y)bPΜ}FV,L7(]@z!h:JjU=6˰/J66-NaܾN6Vap(û&I]u%HiwRT[-3<>>x](@1c`۰JvkkF%H%` >hyӣ ; LWnr8@t0W|gqf\#x}+wm 2p1-RZy F-gi:j+ N;Ӡ5P9gˬFcL\iJ#&wC8{pnF=Bomm9{ΌNc@(f,Bz}Ŷ*b#Sg6DԟV{ Z+Ա B$Ŝ6+ܶ7X˸ ֔cb"L%u璢-K2\LD}iuYsm黧H)-9tZp\0:̑# Z3nf>@;^bM*iXNP.K-+3`Վ+jtyqVS#}jK-u4iW+PȀP$4ΐWWSl OU!j$>VC0,DfgF[L'M'@'!Qj@-sē qZ{HBZesQڼ"bW%`TCי2h4lv)b~&BUPR@`: `җ7vV޵)#!jΫ)0 reizd-:mU# ]HyVt4΋ :kRw@dP'3lH{Dz!`7)͢=WVF!09DtDXxޣ R$?J"˛1,,)ڢּ#`% Yi~ޱv&H F(-H:X~8/4f#~O˗¬nP[u Ot ,s >1F&NJ%;(6Pba#n`l.j"2>9 w]P/W;\)F( ʤ^|k]Y;Jpu\594+#]۶7F&}`Gs:~A ?=oR&(m2e{GHC-o _EH B۶7Tf usfSsZv^ >3K?~Tͮ_eGWx.{xP/ǻipYkr^Tmbc*;~W6yJ"@skljI"FB.2']a?b,'F[D?zkfyɍߐS=`+q{CI'Wˎ۶7Z-HW^Nrz}h˦8hĿplx%ZQ/"HW_31q6.9<q:d_ׄbL<&|ŭ˗O} EAytzM:mM5~ ӷGI\ԅBrFi$2j9,y%8-5Y XN;֦4]kjj _u$ چPlmi@Yr2ug DL09tj 2@('%0)ddc϶{ \N2 n׬^a;04: &y"ؘ\1ڀ^DŲt pacY+lB:eC >,/yx0 O6QR'JrLP 7DN6d"E&H:6"C'Q`=p5Q+ 1x,k6.BWᐬwO/|9b^z[$c1Py1* ?tRWfY(w[IENDB`yubikey-neo-manager-1.4.0/resources/installer_bg.png0000664000175000017500000000041012471132571022421 0ustar daindain00000000000000PNG  IHDRU`bKGD pHYs  tIME  #-.yOIDATx nH@/QIENDB`yubikey-neo-manager-1.4.0/ChangeLog0000644000175000017500000010666212621055513017021 0ustar daindain000000000000002015-11-12 Dain Nilsson * NEWS, neoman/__init__.py: Prepare release. 2015-11-11 Dain Nilsson * doc/Usage.adoc: Add missing space. 2015-11-11 Dain Nilsson * doc/Usage.adoc: Added information about libccid (closes #50). 2015-11-11 Dain Nilsson * neoman/view/applet.py: Don't refresh name if no device is present. Related to #47. This removes an error being logged when removing a device. 2015-11-06 Dain Nilsson * neoman/appletdb.json: Updated some description strings. 2015-11-06 Dain Nilsson * neoman/device_ccid.py: Added workaround for 4.2.4 firmware. 2015-11-05 Dain Nilsson * setup.cfg, vendor/yubicommon: Re-included required data files for PyInstaller build (fixes #42). 2015-11-05 Dain Nilsson * neoman/__init__.py: Bump version. 2015-11-05 Dain Nilsson * NEWS, neoman/view/applet.py: Refresh device name on applet page (fixes #47). 2015-11-05 Dain Nilsson * neoman/device_ccid.py, neoman/device_otp.py, neoman/device_u2f.py, neoman/yk4_utils.py: Remove duplicated code. 2015-11-05 Dain Nilsson * neoman/device_ccid.py, neoman/device_otp.py, neoman/device_u2f.py: Added YK4 support over CCID. 2015-11-05 Dain Nilsson * neoman/device_otp.py, neoman/device_u2f.py, neoman/ykpers.py, vendor/yubicommon: Added YK4 support over OTP. 2015-11-05 Dain Nilsson * neoman/device_u2f.py: Support YK4 over U2F transport. 2015-11-05 Dain Nilsson * resources/osx-patch-ccid: Removed osx-patch-ccid (use ifd-yubico instead). 2015-11-02 Dain Nilsson * README: Update README Change ~ to %7e in URLs so asciidoc stops parsing them as sub text. 2015-10-12 Dain Nilsson * README: Add link to PPA package (fixes #44). 2015-09-16 Henrik Stråth * doc/Manual.adoc, doc/Usage.adoc: Renamed Manual.adoc to Usage.adoc 2015-09-15 Henrik Stråth * doc/Manual.adoc: Fixed Asciidoc syntax error 2015-09-15 Henrik Stråth * doc/Manual.adoc: Restructured Manual.adoc 2015-09-15 Henrik Stråth * doc/Manual.adoc: Flattened subdirectory hierarchy in docs/ 2015-09-15 Henrik Stråth * doc/Manual.adoc: Added doc directory with the PDF manual as Asciidoc 2015-09-10 Henrik Stråth * README: Mentioned minimal OS X version in README 2015-09-02 Henrik Stråth * vendor/yubicommon: Updated yubicommon 2015-08-20 Dain Nilsson * setup.py, vendor/yubicommon: Update yubicommon. 2015-08-20 Dain Nilsson * resources/neoman.nsi, resources/neoman.pkgproj, resources/neoman.spec, resources/osx-installer.pkgproj, resources/qt.conf, resources/win-installer.nsi: Renamed/removed resource files. 2015-08-20 Dain Nilsson * setup.py, vendor/yubicommon: Added longname. 2015-08-20 Dain Nilsson * vendor/yubicommon: Updated yubicommon. 2015-08-20 Dain Nilsson * setup.py: Don't explicitly specify packages. 2015-08-19 Dain Nilsson * neoman/__init__.py: Bumped version. 2015-08-19 Dain Nilsson * resources/osx-patch-ccid: Updated patch to not fail on error. 2015-08-19 Dain Nilsson * README: Updated README instructions for windows code signing. 2015-08-19 Dain Nilsson * : Merge pull request #41 from Yubico/yubicommon Making use of yubicommon 2015-08-19 Henrik Stråth * .gitignore, MANIFEST.in, man/neoman.1.adoc, neoman/__main__.py, setup.py: Man file now generated from adoc. SIGINT now correctly captured. 2015-08-19 Henrik Stråth * neoman/libloader.py, neoman/u2fh.py, neoman/ykneomgr.py, neoman/ykpers.py: Now using libloader from yubicommons instead of bundling libloader. 2015-08-19 Henrik Stråth * neoman/__main__.py, neoman/messages.py, neoman/networker.py, neoman/u2fh.py, neoman/view/main.py, neoman/view/tabs.py: Minor cleanups 2015-08-19 Henrik Stråth * neoman/messages.py, neoman/view/main.py: Readded initial window resizing. 2015-08-19 Henrik Stråth * neoman/model/applet.py, neoman/networker.py: Fixed bug that caused downloading of db_url not to signal on completion. 2015-08-19 Henrik Stråth * setup.py: Cleaned up setup.py 2015-08-19 Henrik Stråth * neoman/__main__.py, neoman/main.py, scripts/neoman, scripts/neoman.1, setup.py: Use entry_points instead of scripts in setup.py. 2015-08-19 Henrik Stråth * vendor/yubicommon: Pulled latest version of yubicommons 2015-06-04 Henrik Stråth * neoman/main.py, neoman/model/applet.py, neoman/networker.py, neoman/view/main.py, neoman/worker.py, qt_resources.py, release.py, setup.py: Now making actual use of yubicommons. 2015-06-04 Henrik Stråth * neoman/yubicommon: Symlinked in yubicommon module 2015-06-04 Henrik Stråth * .gitignore, .gitmodules, vendor/yubicommon: Added submodule for YubiCommon 2015-06-04 Henrik Stråth * README: Fix typo in README 2015-05-18 Dain Nilsson * NEWS, neoman/__init__.py: Update NEWS and version for release. 2015-05-18 Dain Nilsson * neoman/view/main.py: Don't save window position (fixes #36). 2015-05-18 Dain Nilsson * resources/neoman.nsi: Fix name of outfile. 2015-05-08 Dain Nilsson * resources/neoman.spec: Sign using PIV. 2015-05-08 Dain Nilsson * NEWS: Updated NEWS 2015-05-08 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/device_otp.py, neoman/device_u2f.py: Don't show firmware version in CCID mode. 2015-05-07 Dain Nilsson * NEWS: Updated NEWS. 2015-04-28 Dain Nilsson * README: Added OpenPGP security advisory notice. 2015-04-24 Dain Nilsson * resources/osx-patch-ccid: Updated device list in osx-patch-ccid. 2015-04-22 Dain Nilsson * neoman/appletdb.json: Updated appletdb. 2015-04-14 Dain Nilsson * MANIFEST.in, NEWS, neoman/__init__.py: Bump version. 2015-04-14 Dain Nilsson * README: Use https for link in README. 2015-04-10 Dain Nilsson * neoman/__init__.py: Bump version. 2015-04-10 Dain Nilsson * NEWS: Updated NEWS for release. 2015-04-10 Dain Nilsson * neoman/device_u2f.py: Fix allowed modes for NEO devices in U2F mode. 2015-04-10 Dain Nilsson * resources/neoman.spec: Don't build a zip file. 2015-04-10 Dain Nilsson * NEWS: Updated NEWS for release. 2015-04-09 Dain Nilsson * resources/neoman.desktop: Set StartupNotify=false in neoman.desktop. 2015-04-08 Dain Nilsson * neoman/device_ccid.py, neoman/device_otp.py, neoman/device_u2f.py, neoman/exc.py, neoman/messages.py, neoman/view/neo.py: Display error message if mode switching fails (fixes #33). 2015-04-07 Dain Nilsson * resources/linux-fix-ccid-udev: Added YK4 devices to libccid. 2015-04-07 Dain Nilsson * NEWS, neoman/__init__.py, neoman/device.py, neoman/device_otp.py, neoman/device_u2f.py, neoman/main.py, neoman/messages.py, neoman/view/neo.py, neoman/view/tabs.py, neoman/view/welcome.py, neoman/worker.py: Added support for Edge. 2015-02-18 Dain Nilsson * resources/linux-fix-ccid-udev: Added Plus device to udev file. 2015-02-16 Dain Nilsson * resources/linux-fix-ccid-udev: Add Udev file regardless if libccid is installed or not. 2015-02-10 Dain Nilsson * neoman/appletdb.json: Updated appletdb with new U2F AID. 2014-12-08 Dain Nilsson * resources/osx-patch-ccid: Made osx patch more verbose. 2014-12-01 Henrik Stråth * README: Update README 2014-12-01 Henrik Stråth * NEWS: Update NEWS 2014-12-01 Dain Nilsson * resources/neoman.spec: Changed name of Windows installer. 2014-12-01 Dain Nilsson * : Merge pull request #30 from lowks/patch-1 Update setup.py 2014-12-01 Dain Nilsson * NEWS: Updated NEWS for release. 2014-11-27 Dain Nilsson * NEWS, README, neoman/main.py: Font fix for Yosemite. 2014-11-27 Dain Nilsson * neoman/device_otp.py: Fix name. 2014-11-27 Dain Nilsson * NEWS, neoman/__init__.py, neoman/device_otp.py: Added recognition for YubiKey Plus. 2014-11-21 Dain Nilsson * : Merge pull request #27 from jlrgraham/osx_version_number Include correct version number in OS X app bundle. 2014-11-19 Dain Nilsson * resources/linux-fix-ccid-udev: Restart PCSCD. 2014-11-19 Dain Nilsson * resources/linux-fix-ccid-udev: Added script to patch libccid_Info.plist and add Udev rule. 2014-11-19 Dain Nilsson * NEWS, neoman/__init__.py: Bumped version. 2014-11-19 Dain Nilsson * NEWS, neoman/__init__.py: Promoted version to 1.x.x 2014-11-18 Dain Nilsson * NEWS, neoman/__init__.py: Bumped version. 2014-11-18 Dain Nilsson * NEWS, neoman/view/neo.py: Re-enable U2F+OTP modes. 2014-11-10 Dain Nilsson * resources/neoman.desktop: Fix neoman.desktop (fixes #25). 2014-11-03 Dain Nilsson * : Remove OS X installer image (Yosemite partially blocks it from view). 2014-11-03 Dain Nilsson * NEWS, neoman/__init__.py: Bumped version 2014-11-03 Dain Nilsson * NEWS: Updated NEWS for release. 2014-11-03 Dain Nilsson * neoman/model/neo.py: Improved NEO state resetting for Yosemite. 2014-10-31 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/device_otp.py, neoman/device_u2f.py, neoman/model/neo.py: Fix device detection issues with Yosemite. 2014-10-28 Dain Nilsson * : Merge pull request #22 from philipithomas/gitignore Gitignore additions 2014-10-27 Dain Nilsson * NEWS, neoman/__init__.py: Bumped version. 2014-10-27 Dain Nilsson * resources/neoman-large.xpm, resources/neoman.xpm: Updated graphics. 2014-10-27 Dain Nilsson * NEWS: Updated NEWS for release. 2014-10-27 Dain Nilsson * README: Updated README with revised instructions for building binaries. 2014-10-27 Dain Nilsson * resources/osx-patch-ccid: Restart pcscd if running. 2014-10-27 Dain Nilsson * NEWS, resources/neoman.pkgproj: Fixed neoman.pkgproj 2014-10-27 Dain Nilsson * README, neoman/view/main.py: Increase min window height a tad. 2014-10-27 Dain Nilsson * neoman.spec, resources/neoman.spec: Moved neoman.spec to resources/ and added it to the dist 2014-10-27 Dain Nilsson * resources/libccid-yubikey-old.diff, resources/libccid-yubikey.diff, resources/osx-patch-ccid: More robust libccid patching. 2014-10-27 Dain Nilsson * neoman/device_ccid.py, neoman/device_u2f.py, neoman/model/applet.py, neoman/model/neo.py, neoman/view/neo.py, neoman/ykpers.py: Fix formatting. 2014-10-23 Philip I. Thomas * .gitignore: Gitignore additions 2014-10-23 Dain Nilsson * README.adoc: Added README.adoc symlink for Github. 2014-10-15 Simon Josefsson * COPYING: Bump copyright years. 2014-10-14 Dain Nilsson * qt_resources.py, release.py: Use setuptools. 2014-10-14 Dain Nilsson * neoman/__init__.py: Bumped version. 2014-10-14 Dain Nilsson * resources/neoman-large.xpm, resources/neoman.xpm, resources/neoman_large.xpm, setup.py: Updated images and fixed build. 2014-10-14 Dain Nilsson * NEWS, qt_resources.py: Update NEWS for release, fix qt_resources command. 2014-10-14 Dain Nilsson * resources/neoman.xpm, resources/neoman_large.xpm: Provide 32x32 and 128x128 xpm icons. 2014-10-14 Dain Nilsson * NEWS: Updated NEWS. 2014-10-14 Dain Nilsson * .gitignore, MANIFEST.in, neoman/main.py, neoman/view/nav.py, neoman/view/tabs.py, qt_resources.py, setup.py: Compile images into code using pyside-rcc. 2014-10-10 Dain Nilsson * resources/neoman.xpm: Use a higher resolution icon for Linux. 2014-09-26 Dain Nilsson * neoman/__init__.py: Bumped version 2014-09-26 Simon Josefsson * BLURB: Fix URL. 2014-09-26 Dain Nilsson * NEWS, neoman/__init__.py: Updated NEWS and version. 2014-09-26 Dain Nilsson * neoman/view/neo.py: Don't display OTP/U2F mode note for devices without U2F. 2014-09-26 Dain Nilsson * neoman/model/neo.py: Better handle multiple devices with no serial. 2014-09-26 Dain Nilsson * NEWS: Updated NEWS for release. 2014-09-26 Dain Nilsson * NEWS, neoman/device.py, neoman/device_otp.py, neoman/device_u2f.py, neoman/messages.py, neoman/model/neo.py, neoman/view/neo.py: Support unsupported devices. 2014-09-26 Dain Nilsson * neoman/appletdb.json: Updated appletdb with latest applets. 2014-09-26 Dain Nilsson * NEWS, neoman/main.py, neoman/messages.py, neoman/view/neo.py: Disable OTP+U2F compisite modes. 2014-09-23 Dain Nilsson * neoman/view/neo.py: Left-align the U2F label if not showing firmware. 2014-09-23 Dain Nilsson * NEWS, neoman/__init__.py: Bump version and update NEWS. 2014-09-23 Dain Nilsson * neoman/device_otp.py, neoman/ykpers.py: Use yk_get_key_vid_pid to get mode in OTP mode. 2014-09-23 Dain Nilsson * README: Document that multi-device support only works for CCID. 2014-09-23 Dain Nilsson * neoman/view/neo.py: Hide firmware label when unknown. 2014-09-22 Dain Nilsson * README: Use the correct project name: 'yubikey-personalization' (fixes #8). 2014-09-22 Dain Nilsson * README: Clarified dependency copying for building binaries (fixes #8). 2014-09-18 Dain Nilsson * neoman/appletdb.json: Updated appletdb. 2014-09-16 Dain Nilsson * NEWS: Updated NEWS for release. 2014-09-16 Dain Nilsson * neoman/messages.py, neoman/view/tabs.py: Tweak about dialog text. 2014-09-16 Dain Nilsson * neoman/messages.py, neoman/view/welcome.py: Show about button from welcome page. 2014-09-16 Dain Nilsson * README, neoman/view/tabs.py: Changed about dialog icon. 2014-09-16 Dain Nilsson * neoman/messages.py, neoman/view/tabs.py: Added file missing from last commit. Changed about text. 2014-09-16 Dain Nilsson * neoman/device_ccid.py, neoman/device_otp.py, neoman/device_u2f.py, neoman/messages.py, neoman/u2fh.py, neoman/view/applet.py, neoman/view/neo.py, neoman/ykneomgr.py, neoman/ykpers.py: Added about dialog with library versions. 2014-09-16 Dain Nilsson * neoman/messages.py, neoman/view/neo.py: Change FIDO message. 2014-09-15 Dain Nilsson * neoman/messages.py, neoman/view/neo.py: Show if a device is U2F capable. 2014-09-11 Dain Nilsson * neoman/device_u2f.py, neoman/u2fh.py: Updated to changes in libu2f-host. 2014-09-11 Dain Nilsson * neoman/view/main.py: Increased minimum height to prevent clipping on OS X. 2014-09-10 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/device_u2f.py, neoman/view/neo.py: More U2F refinements. 2014-09-10 Dain Nilsson * neoman/device.py, neoman/device_hid.py, neoman/device_otp.py: Renamed HIDDevice to OTPDevice. 2014-09-10 Dain Nilsson * neoman/device.py, neoman/device_u2f.py, neoman/u2fh.py: Updated u2flib-host. 2014-09-09 Dain Nilsson * neoman/device.py, neoman/device_u2f.py, neoman/model/neo.py: Remove prints and dead code. 2014-09-09 Dain Nilsson * neoman/device.py, neoman/device_u2f.py, neoman/model/neo.py, neoman/u2fh.py, neoman/view/neo.py: Added support for multiple U2F devices through libu2f-host. 2014-09-09 Dain Nilsson * README: Updated instructions for building/signing on OS X. 2014-09-09 Dain Nilsson * resources/neoman.pkgproj, resources/osx-patch-ccid: More OSX installer tweaks. 2014-09-09 Dain Nilsson * resources/neoman.pkgproj: Add old patch to pkgproj and no longer require restart (fixes #3) 2014-09-09 Dain Nilsson * resources/osx-patch-ccid: OSX patch tweaks. 2014-09-08 Dain Nilsson * resources/osx-patch-ccid: Fix patch script. 2014-09-08 Dain Nilsson * resources/libccid-yubikey-old.diff, resources/libccid-yubikey.diff, resources/osx-patch-ccid: Improved CCID device list patching. 2014-09-08 Dain Nilsson * NEWS, README, neoman/__init__.py: Bumped version and updated NEWS and README. 2014-09-08 Dain Nilsson * neoman/device_ccid.py, neoman/device_u2f.py, neoman/model/neo.py, neoman/view/nav.py, neoman/view/neo.py: Remove icons for available apps. Minor cleanups. 2014-09-08 Dain Nilsson * neoman/device.py, neoman/device_u2f.py, neoman/u2fh.py: Add support for U2F devices by using libu2f-host. 2014-09-03 Dain Nilsson * resources/libccid-yubikey.diff: Updated OSX libccid patch. 2014-09-03 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/messages.py, neoman/model/neo.py: Deal with YubiKey NEOs in composite mode better. 2014-09-03 Dain Nilsson * neoman/device_hid.py, neoman/messages.py, neoman/view/neo.py: Improved mode switching options. 2014-09-03 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/device_hid.py, neoman/messages.py, neoman/model/modes.py, neoman/model/neo.py, neoman/view/neo.py: Refactored mode handling. 2014-09-02 Dain Nilsson * neoman/main.py: Remove print statement. 2014-09-02 Dain Nilsson * neoman/appletdb.json: Updated appletdb.json 2014-09-02 Dain Nilsson * neoman/appletdb.json, neoman/js_api.js: Re-indent. 2014-09-02 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/device_hid.py, neoman/js_api.js, neoman/messages.py, neoman/model/applet.py, neoman/model/jsapi.py, neoman/model/neo.py, neoman/view/applet.py, neoman/view/neo.py: Added U2F modes. Check installed apps by probing. 2014-09-02 Dain Nilsson * neoman/main.py, neoman/view/nav.py: Introduce devmode and only show installed apps when not activated. 2014-09-02 Dain Nilsson * resources/osx-patch-ccid: Kill pcscd after applying patch 2014-09-02 Dain Nilsson * neoman/appletdb.json: Updated old information 2014-03-25 Dain Nilsson * MANIFEST.in: Updated MANIFEST. 2014-03-25 Dain Nilsson * NEWS: Updated NEWS for release. 2014-03-25 Dain Nilsson * neoman/__init__.py, neoman/device_ccid.py, neoman/model/jsapi.py: Re-auth after deselecting GP. 2014-03-25 Dain Nilsson * NEWS: Updated NEWS. 2014-03-25 Dain Nilsson * neoman/device_ccid.py, neoman/model/jsapi.py, neoman/view/neo.py: Re-select GP after selecting other applets. 2014-03-25 Dain Nilsson * neoman/device_ccid.py, neoman/model/jsapi.py: Fixes. 2014-03-25 Dain Nilsson * neoman/device_ccid.py, neoman/js_api.js: Don't block neomans select commands. 2014-03-25 Dain Nilsson * README, neoman.spec, neoman/appletdb.json, neoman/js_api.js, neoman/model/applet.py, neoman/model/jsapi.py: Auto-select applets for JS API. 2014-03-25 Dain Nilsson * neoman/device_ccid.py, neoman/ykneomgr.py: Add send_apdu command. 2014-03-25 Dain Nilsson * neoman/appletdb.json, neoman/model/applet.py, setup.py: Verify applet db files. 2014-03-24 Dain Nilsson * neoman/appletdb.json, neoman/device_ccid.py, neoman/device_hid.py, neoman/js_api.js, neoman/messages.py, neoman/model/applet.py, neoman/model/jsapi.py, neoman/view/applet.py: Started work on per-applet JS API. 2014-03-21 Dain Nilsson * neoman/storage.py: Removed debug print statement. 2014-03-20 Dain Nilsson * NEWS, neoman/__init__.py: Bumped version. 2014-03-20 Klas Lindfors * neoman/appletdb.json: update text on ykneo-piv 2014-03-20 Dain Nilsson * scripts/neoman.1: Updated man page. 2014-03-20 Dain Nilsson * NEWS: Updated NEWS for release. 2014-03-20 Dain Nilsson * README: Updated build intructions in README. 2014-03-20 Dain Nilsson * resources/neoman.pkgproj: Use relative paths in neoman.pkgproj 2014-03-20 Dain Nilsson * resources/neoman.pkgproj: Added OSX Packages project for building an OSX installer. 2014-03-20 Dain Nilsson * resources/osx-patch-ccid, resources/osx-patch-ccid.sh: rename 2014-03-20 Dain Nilsson * NEWS: Updated NEWS. 2014-03-20 Dain Nilsson * resources/libccid-yubikey.diff, resources/osx-patch-ccid.sh: Added CCID patch for OSX. 2014-03-19 Dain Nilsson * README, neoman/view/applet.py: Fix type. 2014-03-19 Dain Nilsson * neoman/appletdb.json, neoman/messages.py, neoman/model/neo.py, neoman/view/applet.py: Reorganized Applet layout. 2014-03-19 Dain Nilsson * neoman/appletdb.json, neoman/view/applet.py: Updated appletdb. 2014-03-19 Dain Nilsson * neoman/model/applet.py, neoman/storage.py: Only hash after getting a file, and before using it. 2014-03-19 Dain Nilsson * MANIFEST.in, neoman.spec, neoman/model/applet.py: Fix paths for PyInstaller. 2014-03-19 Dain Nilsson * MANIFEST.in: Updated MANIFEST adding icons. 2014-03-19 Dain Nilsson * neoman/main.py, neoman/messages.py, neoman/view/applet.py, neoman/view/main.py, neoman/view/nav.py, neoman/worker.py: Added installation status icons. 2014-03-18 Dain Nilsson * neoman/main.py, neoman/model/applet.py, neoman/view/nav.py, neoman/view/neo.py: Fixed appletdb downloading. 2014-03-18 Dain Nilsson * neoman/device_ccid.py: Fix device leak. 2014-03-18 Dain Nilsson * neoman/appletdb.json, neoman/model/applet.py, neoman/view/applet.py: Prevent uninstallation of Manager and YubiKey OTP applets. 2014-03-18 Dain Nilsson * neoman/appletdb.json, neoman/main.py, neoman/messages.py, neoman/model/applet.py, neoman/storage.py, neoman/view/applet.py, neoman/view/nav.py, neoman/view/neo.py, neoman/worker.py: Externalized applet db. 2014-03-17 Dain Nilsson * neoman/model/applet.py, neoman/view/applet.py: Disable (un-)install button when no device present. 2014-03-17 Dain Nilsson * neoman/device.py, neoman/messages.py, neoman/model/applet.py, neoman/storage.py, neoman/view/applet.py, neoman/worker.py: Implement applet downloading. 2014-03-17 Dain Nilsson * neoman/device.py, neoman/messages.py, neoman/view/applet.py, neoman/view/nav.py: Properly close HID devices before re-opening. 2014-03-17 Dain Nilsson * neoman/view/main.py: Stricter typing of Slot. 2014-03-17 Dain Nilsson * neoman/view/applet.py, neoman/view/main.py, neoman/view/nav.py, neoman/view/neo.py: Reorganized some Signals and Slots. 2014-03-17 Dain Nilsson * neoman/device_ccid.py, neoman/model/neo.py, neoman/view/applet.py, neoman/view/neo.py: Cache applets and re-use devices. 2014-03-14 Dain Nilsson * neoman/device_ccid.py, neoman/exc.py, neoman/main.py, neoman/messages.py, neoman/view/applet.py, neoman/view/main.py, neoman/view/neo.py, neoman/worker.py: Got running blocking tasks in the background to work with callbacks. 2014-03-13 Dain Nilsson * neoman/main.py, neoman/worker.py: Refactored application initialization into subclass. 2014-03-13 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/main.py, neoman/messages.py, neoman/model/applet.py, neoman/model/neo.py, neoman/storage.py, neoman/view/applet.py, neoman/worker.py: Implement applet installation/deletion. 2014-03-12 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/main.py, neoman/messages.py, neoman/model/applet.py, neoman/model/neo.py, neoman/view/applet.py, neoman/view/nav.py, neoman/view/neo.py, neoman/ykneomgr.py: Externalized strings. Updated for libykneomgr 0.0.1 2014-02-10 Dain Nilsson * MANIFEST.in: Removed pyinstaller.py from MANIFEST.in. 2014-01-30 Dain Nilsson * scripts/neoman: Exit on SIGINT. 2013-12-06 Dain Nilsson * neoman/model/neo.py: Fixed device equality check. 2013-11-26 Dain Nilsson * neoman.spec: append_pkg = False for OSX. 2013-11-26 Dain Nilsson * resources/neoman.desktop: Added linux desktop entry. 2013-11-26 Dain Nilsson * NEWS, neoman/__init__.py: Bumped version. 2013-11-26 Dain Nilsson * MANIFEST.in, resources/neoman.xpm: Added XPM for Debian and included resources in the build. 2013-11-26 Dain Nilsson * resources/neoman.nsi: Use modern UI for NSIS. 2013-11-25 Dain Nilsson * neoman.spec, resources/neoman.nsi: Add NSIS installer for Windows. 2013-11-18 Dain Nilsson * neoman/device_ccid.py, neoman/device_hid.py, neoman/model/neo.py: Replaced asserts. 2013-11-13 Dain Nilsson * neoman.spec: Re-fix zipping. 2013-11-13 Dain Nilsson * neoman.spec: Fixed zipping. 2013-11-13 Dain Nilsson * neoman.spec: Added zipping to build process. 2013-11-13 Dain Nilsson * BLURB: Added BLURB 2013-11-13 Dain Nilsson * NEWS: Updated NEWS for release. 2013-11-13 Dain Nilsson * neoman/view/main.py: Increase window width slightly due to margins on OSX. 2013-11-12 Dain Nilsson * neoman/main.py, neoman/view/main.py: fix. 2013-11-12 Dain Nilsson * neoman/view/main.py: Raise window after open. 2013-11-12 Dain Nilsson * neoman.spec, resources/qt.conf: Fix for Qt on OSX looking for plugins in the wrong places. 2013-11-12 Dain Nilsson * neoman.spec: Added version info to Windows build. 2013-11-12 Dain Nilsson * neoman/device_ccid.py: Don't call ykneomgr_done on device that wasn't initialized. 2013-11-11 Dain Nilsson * neoman/main.py: Font fix for OSX Mavericks (QTBUG-32789). 2013-11-11 Dain Nilsson * neoman/libloader.py: Fixed library loading for OSX. 2013-11-11 Dain Nilsson * README: Updated build instructions in README. 2013-11-11 Dain Nilsson * neoman.spec: Sign exe before copy. 2013-11-11 Dain Nilsson * neoman.spec: Import getpass. 2013-11-11 Dain Nilsson * neoman.spec: Added code signing to windows. 2013-11-08 Dain Nilsson * neoman.spec: Improved spec. 2013-11-08 Dain Nilsson * neoman.spec, pyinstaller.py, setup.py: Replace pyinstaller command with .spec file. 2013-11-08 Dain Nilsson * MANIFEST.in, NEWS, pyinstaller.py, setup.py: Added pyinstaller building. 2013-11-07 Dain Nilsson * neoman/view/main.py: Made window smaller to remove some empty space. 2013-11-07 Dain Nilsson * .gitignore, README: Updated README for running tests (there are none currently). 2013-11-06 Dain Nilsson * : Added Windows icon. 2013-11-06 Dain Nilsson * : Replaced icon. 2013-11-06 Dain Nilsson * neoman/device_ccid.py: Properly dispose of the NEO handle if init/discover fails. 2013-11-05 Dain Nilsson * NEWS, setup.cfg: Updated NEWS for release. 2013-11-05 Dain Nilsson * neoman/libloader.py: Fixed library loading on Windows broken by earlier commit. 2013-11-05 Dain Nilsson * MANIFEST.in, scripts/neoman.1: Added man page. 2013-11-05 Dain Nilsson * MANIFEST.in, NEWS, README, neoman/device.py, neoman/main.py, neoman/model/neo.py, neoman/view/main.py, neoman/view/nav.py, neoman/view/neo.py: Release preparations. 2013-11-04 Dain Nilsson * neoman/view/nav.py, neoman/view/welcome.py: Only display welcome page when no NEO is inserted. 2013-11-04 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/model/neo.py, neoman/view/neo.py: Added 0x8X modes to mode selection dialog. 2013-11-04 Dain Nilsson * neoman/libloader.py: Better support for loading libraries. 2013-10-30 Dain Nilsson * neoman/libloader.py, neoman/ykneomgr.py, neoman/ykpers.py: Better library loading for Windows. 2013-10-30 Dain Nilsson * neoman/ykneomgr.py: Correctly load libykneomgr-0.dll on Windows. 2013-10-30 Dain Nilsson * README, neoman/device.py, neoman/view/main.py: Updated build instructions. 2013-10-30 Dain Nilsson * neoman/device.py, neoman/device_hid.py: Fix HID version checking. 2013-10-30 Dain Nilsson * neoman/device_ccid.py, neoman/device_hid.py: Don't open YubiKeys with firmware < 3. 2013-10-30 Dain Nilsson * neoman/model/applet.py, neoman/view/main.py: Added version number in title. 2013-10-30 Dain Nilsson * neoman/main.py, neoman/model/neo.py, neoman/view/nav.py, neoman/view/neo.py: Made the available NEO list global. 2013-10-30 Dain Nilsson * neoman/__init__.py, setup.py: Moved version number declaration to neoman/__init__.py 2013-10-30 Dain Nilsson * neoman/model/neo.py, neoman/view/neo.py: More robust device detection. 2013-10-29 Dain Nilsson * neoman/model/neo.py, neoman/view/neo.py: Fixed default transport key. 2013-10-29 Dain Nilsson * neoman/device_ccid.py, neoman/model/applet.py, neoman/model/neo.py, neoman/view/main.py, neoman/view/neo.py: prompt for and save transport keys. 2013-10-29 Dain Nilsson * neoman/device_ccid.py: Fix locked boolean of CCID device. 2013-10-28 Dain Nilsson * neoman/model/neo.py, neoman/view/neo.py: Require device removal upon mode change. 2013-10-28 Dain Nilsson * neoman/__init__.py, neoman/device.py, neoman/device_ccid.py, neoman/device_hid.py, neoman/libloader.py, neoman/main.py, neoman/model/__init__.py, neoman/model/applet.py, neoman/model/neo.py, neoman/storage.py, neoman/view/__init__.py, neoman/view/applet.py, neoman/view/main.py, neoman/view/nav.py, neoman/view/neo.py, neoman/view/welcome.py, neoman/ykneomgr.py, neoman/ykpers.py: Added copyright headers. 2013-10-28 Dain Nilsson * neoman/model/neo.py, neoman/view/nav.py, neoman/view/neo.py: Made device polling asynchronous. 2013-10-28 Dain Nilsson * neoman/device_ccid.py, neoman/ykneomgr.py: Updated libykneomgr. 2013-10-08 Dain Nilsson * neoman/model/neo.py: Stop polling when the window doesn't have focus. 2013-10-08 Dain Nilsson * neoman/model/applet.py, neoman/model/neo.py: Fix problem with failing to release devices. 2013-10-07 Dain Nilsson * neoman/view/applet.py, neoman/view/main.py: Added AppletPage. 2013-10-07 Dain Nilsson * neoman/model/applet.py, neoman/view/neo.py: Added installed applet list. 2013-10-04 Dain Nilsson * neoman/model/applet.py, neoman/view/nav.py, neoman/view/neo.py: Started adding applets. 2013-10-04 Dain Nilsson * neoman/device_ccid.py, neoman/model/neo.py, neoman/view/main.py, neoman/view/nav.py, neoman/view/neo.py, neoman/ykneomgr.py: Removed neo removal signal (not needed). 2013-10-04 Dain Nilsson * neoman/view/main.py, neoman/view/neo.py, neoman/view/welcome.py: Return to start page on device removal. 2013-10-04 Dain Nilsson * neoman/device_hid.py, neoman/main.py, neoman/model/neo.py, neoman/storage.py, neoman/view/main.py, scripts/neoman: Added persistant storage. 2013-10-03 Dain Nilsson * neoman/device_hid.py, neoman/model/neo.py, neoman/view/neo.py: Signal when a NEO is removed. 2013-10-03 Dain Nilsson * README, neoman/view/main.py, neoman/view/mainwin.py, scripts/neoman: Renamed mainwin.py -> main.py 2013-10-03 Dain Nilsson * neoman/model/neo.py: Store device name in memory. 2013-10-03 Dain Nilsson * neoman/model/neo.py: Fix mode switching. 2013-10-03 Dain Nilsson * neoman/device_ccid.py, neoman/device_hid.py, neoman/model/device.py, neoman/model/devices.py, neoman/model/nav.py, neoman/model/neo.py, neoman/view/device.py, neoman/view/mainwin.py, neoman/view/nav.py, neoman/view/neo.py, neoman/ykneomgr.py: Refactored classes. 2013-10-03 Dain Nilsson * neoman/device.py, neoman/device_ccid.py, neoman/device_hid.py, neoman/model/devices.py, neoman/model/nav.py, neoman/neo.py, neoman/view/device.py, neoman/view/mainwin.py, neoman/ykneomgr.py, neoman/ykpers.py: Added basic support for listing devices and reading serial/version. 2013-10-01 Dain Nilsson * neoman/model/device.py, neoman/model/nav.py, neoman/neo.py, neoman/view/device.py, neoman/view/mainwin.py, neoman/ykneomgr.py, neoman/ykpers.py, setup.py: Added ykneomgr lib. 2013-10-01 Dain Nilsson * neoman/model/__init__.py, neoman/model/device.py, neoman/model/nav.py, neoman/view/device.py, neoman/view/mainwin.py, neoman/view/test.py, neoman/view/test.qml, scripts/neoman: Removed QML, added navigation. 2013-09-27 Dain Nilsson * MANIFEST.in, neoman/__init__.py, neoman/libloader.py, neoman/view/__init__.py, neoman/view/test.py, neoman/view/test.qml, neoman/ykpers.py, scripts/neoman, setup.py: Added Added proof of concept 2013-09-27 Dain Nilsson * Initial commit. yubikey-neo-manager-1.4.0/doc/0000775000175000017500000000000012621055514016004 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/doc/Usage.adoc0000775000175000017500000000651412620663551017716 0ustar daindain00000000000000== YubiKey NEO Manager Manual === Using CCID on OSX and Linux To be able to use any of the smartcard functionality of your YubiKey NEO, you will need an up to date version of libccid (1.4.20 or later is recommended). Often an older version will work, but will require modification to detect the YubiKey in certain modes. To make this modification easier, we provide a link:https://github.com/Yubico/ifd-yubico/releases/download/ifd-yubico-1.0.0/ifd-yubico.pkg[packaged installer for OSX], as well as a link:https://github.com/Yubico/yubikey-neo-manager/blob/master/resources/linux-fix-ccid-udev[script for Linux]. Windows users do not need to take any action. === Change connection mode In order to enable or disable modes on your YubiKey NEO or NEO-n, you need to download the newest version of the Yubico NEO Manager. The NEO Manager is available for Windows, OSX and Linux, and installers can be downloaded from the Yubico website using the links below. * NEO Manager for Windows: http://yubi.co/NEOMgrWin * NEO Manager for OSX: http://yubi.co/NEOMgrMac * NEO Manager for Linux: http://yubi.co/NEOMrgLux Once downloaded, you will need to install the NEO Manager using the default options. Once installed, launch the NEO Manager application to proceed. image:image1.PNG[image] If a YubiKey NEO or NEO-n is not inserted in your PC, the NEO Manager will prompt you to insert your YubiKey to continue. In order to change settings with the NEO Manager, only one YubiKey NEO or NEO-n device can be plugged into your computer. image:image2.PNG[image] To enable any desired combination of U2F, OTP and CCID modes, you will need to click image:image5.PNG[image]. image:image6.PNG[image] Clicking image:image5.PNG[image] will open up a window allowing you to check boxes for OTP, CCID and U2F. Checking the boxes will enable that functionality on the YubiKey NEO and NEO-n. image:image7.PNG[image] * The OTP mode refers to the YubiKey functions the NEO shares with the standard YubiKey, including two Configuration Slots that can be programmed with any two of the following: Yubico OTP (programmed by Yubico in Slot 1, by default), OATH-HOTP, Challenge-Response and Static Password. * The CCID Mode refers to the smart card elements on the YubiKey NEO and NEO-n, and includes the NEO applets such as OpenPGP, PIV and YubiOATH. * The U2F Mode refers to the Universal 2^nd^ Factor (U2F) functionality of the YubiKey NEO and NEO-n. image:image8.PNG[image] Once the desired modes are selected, click image:image9.PNG[image] to confirm the selections. The NEO Manager will instruct you to remove your YubiKey from the USB slot, then plug it back in. This will allow the YubiKey to initialize all of the selected modes. image:image10.PNG[image] Your YubiKey NEO or NEO-n will now work in the selected modes. === Renaming a YubiKey The NEO Manager will allow you to optionally set a unique name for your YubiKey NEO or NEO-n, in order to better identify it when you have multiple YubiKeys. This can be done by clicking image:image3.PNG[image] – doing so will open a new window allowing you to change the name of the YubiKey NEO or NEO-n. Please note that if you have NEO Manager installed on multiple computers, the name change will only be reflected on the computer the change was made on. image:image4.PNG[image] yubikey-neo-manager-1.4.0/qt_resources/0000775000175000017500000000000012621055514017755 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/qt_resources/icon_about.png0000664000175000017500000000100512471132571022603 0ustar daindain00000000000000PNG  IHDR bKGD pHYs  tIME  #6įiTXtCommentCreated with GIMPd.eiIDAT8˵o@?8, pmBR;Mղ`K0S`CO8b(pWdv i=wOޏWq,ra{U2W{ޤ/8?-QU\J9^AxodxMWI6v5BCvײ>?vȒ-U$}9?*mWn`׏*N^=pJG7pwID9m>:G_2UMW8|$i= L'~hU^6_Vb΍%;kCbS/mDdU=?E9tմMKWYPxYz],x .|&*5%iox6A4mzFK#qw+lzde-x1䃽x )|?gӁt y56-8)݊f|QVdhݒ6Y& D ĕ/`{ǒLw;e1%Cb.UPQvfNFU_0F]xxCILIwAI?PX3hШ,j̸>滨zܐw#77$NA,jDj! 89e.O ԕ5SڰK6Nb-t&g,*ŀ]u0z ƽw hsl=„Έdr$ 6 egpB)sPrC@`ocx8+EN{!BX:u#9bNX mUNE'fidN]i3vّ1=Z-~QE ,acXdFg]ysڳSt)}2kSlbo%G`l&`QWj9'([06}*YYLC2Ýpo zzq]lz.k}#^bʴW>o`NN7ɌAp\ nURoYU&8Ü:cūv'V.A*Fx'1i{=q Y_Q* t.: (Tb$Gؙ}2!:uҭ8S~hj &,;*K::7;MjXnK[^)NMa"f̷zpɊS4W-kCvDV"6!(ec8tw.;F"}(1u*aֺ۲Ug']CƂ7SqJy~(G'JGƀ'6 z}.K6v5Lc-Y(F?TEV`hyN޷GEa9Qd8Sap/f4/J?җS7?b*] k$5Eb)Ӌ`+T;‰J/ \LچKV9,`ƾ ǀHpF?αoGx#{DDS0!p8|%$8R,֧1[0x sU.W\怿)(\?FJx]IENDB`yubikey-neo-manager-1.4.0/qt_resources/icon_installed.png0000664000175000017500000000071412471132571023456 0ustar daindain00000000000000PNG  IHDRabKGD pHYs  tIME 0iTXtCommentCreated with GIMPd.e0IDAT81KqObH t %89Jo Pp|]upVIpҡK;D.qJ!Hxq2xEo̓WVjK}ח:B]nWĺy>tJ]rR!օZ0z MDّ5p^Y3| vK@+aIY*>!3S9frCCP$hn#@} b_JIBl0`icIjyR>v7ˢ:U/_bPQIENDB`yubikey-neo-manager-1.4.0/qt_resources/icon_some_installed.png0000664000175000017500000000066412471132571024505 0ustar daindain00000000000000PNG  IHDRabKGD pHYs  tIME 1G3iTXtCommentCreated with GIMPd.eIDAT8һ/CܖH bXK1Ą" Z-m]zڜ .\" Date: 11/12/2015 .\" Manual: YubiKey NEO Manager Manual .\" Source: neoman .\" Language: English .\" .TH "NEOMAN" "1" "11/12/2015" "neoman" "YubiKey NEO Manager Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" neoman \- Graphical tool for configuring a YubiKey NEO .SH "SYNOPSIS" .sp \fBneoman\fR .SH "DESCRIPTION" .sp YubiKey NEO manager is a graphical utility to configure and program YubiKey NEO devices\&. .SH "BUGS" .sp Report bugs in the issue tracker (https://github\&.com/Yubico/yubikey\-neo\-manager/issues) yubikey-neo-manager-1.4.0/man/neoman.1.adoc0000664000175000017500000000060412565113112020252 0ustar daindain00000000000000neoman(1) =========== :doctype: manpage :man source: neoman :man manual: YubiKey NEO Manager Manual == Name neoman - Graphical tool for configuring a YubiKey NEO == Synopsis *neoman* == Description YubiKey NEO manager is a graphical utility to configure and program YubiKey NEO devices. == Bugs Report bugs in the issue tracker (https://github.com/Yubico/yubikey-neo-manager/issues) yubikey-neo-manager-1.4.0/PKG-INFO0000664000175000017500000000130512621055514016333 0ustar daindain00000000000000Metadata-Version: 1.1 Name: yubikey-neo-manager Version: 1.4.0 Summary: Tool for managing your YubiKey NEO configuration. Home-page: https://github.com/Yubico/yubikey-neo-manager Author: Yubico Open Source Maintainers Author-email: ossmaint@yubico.com License: BSD 2 clause Description: This is the long description Platform: UNKNOWN Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: X11 Applications :: Qt Classifier: Intended Audience :: End Users/Desktop Classifier: Topic :: Security :: Cryptography Classifier: Topic :: Utilities yubikey-neo-manager-1.4.0/neoman/0000775000175000017500000000000012621055514016514 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/neoman/ykpers.py0000664000175000017500000001023312617063403020403 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from ctypes import (Structure, POINTER, c_int, c_uint8, c_uint, c_ubyte, c_char_p) from neoman.yubicommon.ctypes.libloader import load_library _lib = load_library('ykpers-1', '1') def define(name, args, res): try: fn = getattr(_lib, name) fn.argtypes = args fn.restype = res except AttributeError: print "Undefined symbol: %s" % name def error(*args, **kwargs): raise Exception("Undefined symbol: %s" % name) fn = error return fn YK_KEY = type('YK_KEY', (Structure,), {}) YK_STATUS = type('YK_STATUS', (Structure,), {}) YK_TICKET = type('YK_TICKET', (Structure,), {}) YK_CONFIG = type('YK_CONFIG', (Structure,), {}) YK_NAV = type('YK_NAV', (Structure,), {}) YK_FRAME = type('YK_FRAME', (Structure,), {}) YK_NDEF = type('YK_NDEF', (Structure,), {}) YK_DEVICE_CONFIG = type('YK_DEVICE_CONFIG', (Structure,), {}) ykpers_check_version = define('ykpers_check_version', [c_char_p], c_char_p) yk_init = define('yk_init', [], c_int) yk_release = define('yk_release', [], c_int) yk_open_first_key = define('yk_open_first_key', [], POINTER(YK_KEY)) yk_close_key = define('yk_close_key', [POINTER(YK_KEY)], c_int) yk_get_status = define('yk_get_status', [ POINTER(YK_KEY), POINTER(YK_STATUS)], c_int) yk_get_serial = define('yk_get_serial', [ POINTER(YK_KEY), c_uint8, c_uint, POINTER(c_uint)], c_int) yk_write_device_config = define('yk_write_device_config', [POINTER(YK_KEY), POINTER(YK_DEVICE_CONFIG)], c_int) ykds_alloc = define('ykds_alloc', [], POINTER(YK_STATUS)) ykds_free = define('ykds_free', [POINTER(YK_STATUS)], None) ykds_version_major = define('ykds_version_major', [POINTER(YK_STATUS)], c_int) ykds_version_minor = define('ykds_version_minor', [POINTER(YK_STATUS)], c_int) ykds_version_build = define('ykds_version_build', [POINTER(YK_STATUS)], c_int) ykp_alloc_device_config = define('ykp_alloc_device_config', [], POINTER(YK_DEVICE_CONFIG)) ykp_free_device_config = define('ykp_free_device_config', [POINTER(YK_DEVICE_CONFIG)], c_int) ykp_set_device_mode = define('ykp_set_device_mode', [POINTER(YK_DEVICE_CONFIG), c_ubyte], c_int) yk_get_key_vid_pid = define('yk_get_key_vid_pid', [POINTER(YK_KEY), POINTER(c_int), POINTER(c_int)], c_int) yk_get_capabilities = define('yk_get_capabilities', [POINTER(YK_KEY), c_uint8, c_uint, c_char_p], c_int) __all__ = [x for x in globals().keys() if x.lower().startswith('yk')] yubikey-neo-manager-1.4.0/neoman/qt_resources.py0000664000175000017500000003215312621055514021610 0ustar daindain00000000000000# -*- coding: utf-8 -*- # Resource object code # # Created: Thu Nov 12 10:26:36 2015 # by: The Resource Compiler for PySide (Qt v4.8.4) # # WARNING! All changes made in this file will be lost! from PySide import QtCore qt_resource_data = "\x00\x00\x01\xcc\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07tIME\x07\xde\x03\x13\x0a0\x13\xb7\x83\xa7\xa5\x00\x00\x00\x1diTXtComment\x00\x00\x00\x00\x00Created with GIMPd.e\x07\x00\x00\x010IDAT8\xcb\xcd\xd21K\x9bq\x10\xc7\xf1ObH\x09\xcf\x10t\x08\xe4\xa9\x06\x0a%89\xd9J\xc0\xa1\xa3o \xb3P\xe8\xec\x1bp\x11|\x01]upV\xe2\x9aIp\xc9\xd2\xa1K;D\x9a.\xad\xda\xff\x10\xa4\xa1\xa0qJ\xd2!\x8f\x81H\x12\x92\xcd\xdfx\xbf\xbb\xef\xddq\x97\xb2\xa8\x822\xeax\x8b\xc3E\x8b\xdf\x08\xfe\x08\x06\x82o\x82\xf5\xcc\x93W\xadV\x07\xb3j\xfbK}\x97\xd7\x97:\xa5\x8eB\xab\xa0]nW\xc4\xba\xe9y\x9b\xb7>\xb4tJ\x1d\xd1]\xa4rR!\xd6\x85\xcc\xf3\xc4Z\xad\x96\x9a0z\x09MD\x9b\xa7\x9b\xb2\x8f\xd9\x915\xef\x04\xfb\x88p^\xf8Y\x183\xc6\x00\xdd|\x97 \xff\xac\xfb\x1av\xd1K@\x93\x01\x0f+\x0f\xea\x07\xf5aI\xf0Y\xf0*\xb1>!\x8b3\xb1\x1fS\x01\xb9\x7f9\xc5f\x11r\xd8CCP\xc4\xc7$\xe5h\xd2n#@\xba\x97\xb6}\xbc\x0d\xef\xf1\x0b\xef\xf0\x05\xaf\xf1\x1b\x8d\x99\x80\x91b_\xb1\x85\x16JI\xf4Bl0\x1f`\x08ic\x07\xf7I\xe4j\xdayR\xb3>\xf1v\xe3\x96\x14\xcb7\xcb\xa2\xbf\xd1\xc4\x7f\xc9\xcc:\xfe\xea\xf7U/_\xff\x01b\x88P\x1b\xd1\xc6\xe2Q\x00\x00\x00\x00IEND\xaeB`\x82\x00\x00\x00\xd5\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07tIME\x07\xde\x03\x13\x0a1%a\x22\x03}\x00\x00\x00\x1diTXtComment\x00\x00\x00\x00\x00Created with GIMPd.e\x07\x00\x00\x009IDAT8\xcbc`\x18h\xc0\x08c\x84\x86\x86\xfe'E\xe3\xea\xd5\xab\x19\x19\x18\x18\x18\x98(u\x01\x0b.\x93q\x01t\x97R\xec\x82Q\x03\x06\x83\x01,\x84\xe2\x99\xe6.\x18x\x00\x00r\x01\x0a\x1a]I8\xe0\x00\x00\x00\x00IEND\xaeB`\x82\x00\x00\x02\x05\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x00\x14\x00\x00\x00\x14\x08\x06\x00\x00\x00\x8d\x89\x1d\x0d\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07tIME\x07\xde\x09\x10\x0b#6\xc4\xaf\xef\x08\x00\x00\x00\x1diTXtComment\x00\x00\x00\x00\x00Created with GIMPd.e\x07\x00\x00\x01iIDAT8\xcb\xb5\x95\xafo\xc2@\x14\xc7?\x05\x048,\x0apmBR;\xc7M\xd5\xb2\xff`K0S\xb0\xbf\xa0\xb9\xbf`C\xeeO\x98\x1a\xa2\xe6\xd48\x8f\xc1\x81b(pW\x81\x84d\x86v\x0di\xef\x96\x90=\xd5w\xf7\xbdO\xde\x8f\xbcW\x0f\x87\xc5q,\x8a\xbe\x94ra\xd3{\x16\xc8\x04\x18U\xbc\x9b\x03\xb32\xb8W\x02{\x05\xa6\xfc\xcd\xde\xa4\x94/\x95\xc08\x8e?-QU\xd9\x5cJ\xf9\x909\xf5\xab\xc8\x1e\xcb^\x04A\xc0x\x0a\x0aicon_about.png\x0aneoman.png\x0aicon_installed.png\x0aqt_resources.qrc\x0aicon_some_installed.png\x0aicon_not_installed.png\x0a\x0a\x0a\x00\x00\x09R\x89PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\x00\x000\x00\x00\x000\x08\x06\x00\x00\x00W\x02\xf9\x87\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x00\x09pHYs\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07tIME\x07\xde\x0a\x0e\x0b9/\xe7\x8f\xe7o\x00\x00\x00\x1diTXtComment\x00\x00\x00\x00\x00Created with GIMPd.e\x07\x00\x00\x08\xb6IDATh\xde\xc5\x9amlS\xe7\x15\xc7\x7f\xf7\xda\xb1\x89\xf3B^L\xb2\x94\x10')I\x03\x1d/\xa5\xa5I \x14\xe7\xcb\x90h\xd9P\xa5\xee\x1d4Qi\xd3\xb4\x0f\xdb:WUU\x98T!\xfa\xa12H\x93\xa6IU\xa5\x22\x15iUWib\xeb\xba\xa9l\xab\x03iF\x15\xc2\xebX\x03\x09\x858$,$!\xc1\x8e\x13'\xf6}\xd9\x87<\x09\xbe\xbe\xd7\x8e\x1d\xdc\xee\xe4S\xec{\xcfs\xces\xces\xce\xff\xfc\x1fK\xe4P\xfc\x1d\xed\x0e`\x05\xe0\x04lI_\xab\xc0\x1c0\xeb\xf3\x06b\xb9ZS\xca\x81\xd1%\xc03\xc0\x16\xa0\x09\xa8\x03V\x03\xc5\x09\xfau \x0c\x0c\x03\xb7\x80k@\x0f\xd0\xe5\xf3\x06&\xff/\x0e\xf8;\xda\xeb\x81\x83\xc0nal~\x96*\xa2\xc0\x14\xf0\x11\xf0\xba\xcf\x1b\x08~%\x0e\xf8;\xda\xd7\x00\xaf\x02?%\xb7\xf2\x16\xf0\x06p\xdb\xe7\x0d\xe89w\xc0\xdf\xd1^\x08\xbc\x04\xfc\x1c(\xe3\xcb\x91\x09\xe07\xc01\x9f7\x10\xc9\x99\x03\xfe\x8e\xf6J\xe0\xaf\x22\xcf\xd3\x8a\xaekhh\xe8\xba&R\x7f~\x19I\x92\x91\x91\x91$9\x93%/\x02\xbb}\xde\xc0\xc8C;\xe0\xefh\xdf\x0c\x9c\x03\xec\x96\x06\xa3#\x01\x0e\x9b\x0b\x87\xdd\x85\xdbUGeQ#e.\x0f\xf9y\xc5\xf3\xc9\x1e\x0f31\x13\xe4n\xa4\x9f\xb1\xe9\x9b\xc4\x95\x19b\xea\x0c\xfa\xbck\xa9\x96\x8e\x01O\xfb\xbc\x81\xcb\xcbv\xc0\xdf\xd1\xfeM\xe0\x0f\xa2,\x9aLW\xb4\x18\x95\x85\x8d4\xacj\xc3S\xba\x95\xaa\xa2u\xd8\xe4\xbc\xb4\x1b\xa2\xe9\x0aw\xc2\xbd\x04'\xce\xd1?\xde\xc9H\xa4\x8f<\xd9\x91\xca\x94Y\xe0{>o\xe0d\xd6\x0e\x88\x9d\xff\xcc\xcaxMW\xb1I6v5\xbdBC\xf9\x0e\x1cv\xd7\xb2\x12>\xa6\xce\xd0?v\x86\x8f\xaf\xbf\x89\xaa\xab\xc8\x92-U$\x9a}\xde\xc0\xa5\x8c\x1d\x109?\x94*m\xaaWn`\xef\xd7\x8f\xe0\xb4\x17\xe6\xe4\xe4\xce*\x11N^=\xc8p\xe8J\xaaG\xe2\xc0\x1a\x9f7pwI\x07D\xb59m>\xb0:\xaa\xa6\xb0\xad\xeeG\xb4\xd6\xec_2U\xb2\x15MW8\x1b|\x97\xae\x81\xe3\xd8$\xbb\x95i=\x80\xd7\xe7\x0dL'~hU\x12^\xb2\xaa6\xaa\xa6\xf0\xdc\xfa_\xd3V\xfbb\xce\x8d\x07\x90%;\xdbk\x0f\xf0\xec\xbaC\xa8\xbab\xf5\xc8S\x80/m\x04D\x93\xbadU\xe7\x9b=?\xa0\xad\xf6E\xc39\xd0t\xd5\xb4\x8aM\xceKWYP\xb5\x18\xba\xc9x\x19Yz\x90\xad]\x03\xc7\xf9,x\xc2\xea\xf5\x10\xb0\xd1\xe7\x0d\x0c.|\x90\x9c\xe3\xaf&\x1b\xaf\xe9*5%\x9bi\xad\xd9ox\xf0\xbf\xe1\xcf\xe9\xbe\xfd\x1e6\xe9A4\x14m\x8e\xe6\x9a\xef\xb3z\xe5FK\xe3#\xb1q\xfe\xdew\xcc\xf0\x8e\xaa+lzd\x0f\xf5e-\x8b\x9f\xb5x\xf61\x14\xba\xcc\xe0\xe4\xc5\xe4\x83\xbd\x12x\x0d\xf8\x89)\x02\x02\xdb|\x91\x9c\xf7\x12\x12?\xdb\xfeg\xd3\x81\xd5t\x0d\x7f\xc7\xce\xf9\x05\xa4y5\x9a\x16\xa7\xae\xbc\x85\x176\xfa-\x1d8\x1b<\xc1\xe9/~\x87\xdd\xb6b\xa1\xeb\xa1\xe81~\xf5\xcc?\xc9\xb3\x19\xa1\xd4\x9c2\xc5o\xbb\xbe%\x9a\xa1)\xa2\xb5\x0b\xd8)\xf1\x0c\x1cL~J\xd1b\xecjz\xc5\xb2\xda\xc8\x92\xcc\x96\xea\xe7Qu\x05I\xfc\xd9d\x077\xc6?%\x1a\x0fY:pi\xf8\x8f\xd8e\xe7\xe2\xf3\x9a\xae\xb0\xa9j\x8f\xc9x\x00\xa7\xbd\x88]\x8d/\xa3h\x96\xc8\xfb5\xc3!\x16\x90xwr\x87\xad,l\xa4\xa1|G\xca|\xde\xb2\xfayQ1\x1e\x88]v\xd0}\xfb\xf7\xa6g\x87BW\x08\xcd\x8e\x18\xa0\x84$\xd9x\xb2\xfa\x85\x94\xfa\x1b+\xbcT\x146\xa0\x9bN\x0d{\xfc\x1d\xed\xc5\x89\x11xF@b\xc3\xe9nX\xd5\x96\xb6I\x159+XS\xfa\x84a\x01Y\xb2s}\xf44\xaa\x167<{~\xe8\x03\xec\xb2\xd3\xb0A5%\x9b)\xcd_\x9dR\xbf\xc3\x96\xcfc\xabvZ\x95\x84\x95\xc2\xe6E\x07\xb6$\xe3y\x87\xcd\x85\xa7tk\xda\xd2\x97g\xcb\xa7\xbe\xac\xc5Tu\xa2\xf1\x10\xc1\xc9\xf3\x09\xff\xdfg(\xf4o\xe3\xee#Q_\xdej\x99>\x89\xe2)\xdd\x8a\xc3f\xda\xc4|QV\x91\xc5\x18\xd8d\xf2\xde\xee\xa2\xaah\xdd\x92\xf5\xbb\xbe\xbc\x05\x87\xbd\xc0\xd86\xb5Y\x06&\xcf\x09D\x0a\xc1\xc9\x0b\xc4\x95\x99\xa4\x1c/`\xad{\xc7\x92\xfa\xab\x8a\x9bL\xfa\x85\xac\xf7w\xb4;e1\xc3\xd6%Cb\xb7\xab.\xa3\x86U\xee\xf2PQ\xb8v\xd1\xd8\x05\x19\x98\xe8fN\x9dF\xd3U\x06\xef_0\x1cF]\xd7x\xa4xC\xda\xf4ILIwA\x9dI?P\x0f\xac\x90\x05X3h\xd2\xd0\xa8,j\xcc\xb8\x8b>\xbd\xe6\xbb\xa8z\xdc\x90\x1ew#7\xb87\x1d$\xa6N\x13\x9c\xe8A\x92\xa4\x84\xda\x1f\xa7\xb5\xf6\x87\x19\xeb\xaf,jD\xc3\xe4\xc0j\xc0!\x0b\xf6\xa089\x02e.O\xc6\x0b\xd4\x955S\x92\xbf\xda\xb0K6\xc9N\xcf\xed\xf7\x99\x98\x19\xe4\xde\xcc\xe0b-\xd7t\x95\xaa\xa2&\xaa\x8a\xd6g\xac\xbf,\xbf\xc6*\x02\xc5\x80]\xb6\x06u\xfa\xe20\x92\xa9\xb4z\xf6\x13\xd7\xe6\x0c\x90\xe2\xc6\xbd\x7f\xf1\xe9\xadw\x0c\xa9\xa8hsl\xab=\x90\x95\xee\x15\xf6\xc2\x84\xe9\xce\x88\xe3dr$\x0d\xee6\x0a\x1de\xa6\xa1gp\xf2B\x02\x1c\xd0)s\xd5P\xbdrC\xee@`\x02oc\xe8\x02\xd1x8+EN{!\x8f\xba\xb7\x99B\x9dX:u\xa0\xc1\xbd#\xeb9bN\x89X\xc1\x09m\xc1\x01U\x90N\x86E'f\xb2\xa3id\xc9N]i3v\xd9\x91\xb61=Z\xbe-\xd3\xc1~Q\xeeE\x07\xad\xde\x09\x03\x8a,\xe8\xbeacXd\xeeF\xfa\xb3\x0eg]ys\xda\xb3S\xe8t\xe3)}2k\xbd\xa3S\xfd\xc8\xe6l\x1f\x02b\xb2\x18\x9co%G`l\xfa&\x9a\xf5`\x91\xe6\xb0\x15QW\xdej9'(\xda\x1c[\xab\xbf\x9d\xb5\xf1\xaa\xae06}\xd3*\x02\xb7\x80YY\x10\xad\xd7LC\xa82\xc3\x9dpo\xd6\x0b\xb6z\xf6\x19z\xc2\x02\xeeq\xd8]l\xa8z.k}#\xe1^b\xca\xb4\xd5W\xbd>o`NN\x987\xa3\xc9\x8cAp\xe2\x5c\xd6\x0b\xde\x09\x7f\x8e\x94\x14nU\x8b\xd1R\xb3oYU&8\xd9\xc3\x9c:c\xc5\xabv'V\xa1.A\xb4\x1a*F\xffx'1\xf3\xcbi\xa5{\xf0=\x13\x04q\xda\x0bY_\xf9\x8d\xac\x8d\x8f\xabQ\xae\x8f\x9d\xb6\xfa*\x0ct.: (\xee\x8f\x8c\x85Tb$\xd2G\xff\xd8\x99\x8c\x17\xbc}\xff2\x93\xd1!\x03:\xd5u\x8d\xda\xd2\xad\x148\xb2\xa7S\xaf\x8d~\xc2h\xa4\xdfj\xc6\xfe\xd0\xe7\x0d\x84\x93\x1b\xd9\xeb&\xb8,;\xf8\xf8\xfa\x9b\xcc*K\xf3\xac::7\xc6;M\xf9j\x93\xf3X\xebnK[^\xad\xb9\xa2)N\xf5\x1dM\xf5\xdea\x13\xad\x22f\xcc\xb7\x92\x1b\x9a\xaa\xab\x9c\xbczp\xc9\x8a\x14S\xa6\xe9\x1f\xef4\x80\xb6\xc5\x06W\xbe-k\x8e\xe8\xe4\xd5C\xa2\x9a\x99v\xff\xedDV\x22\xb96\xbd!(\xee\x84\x06ec8t\x85\xb3\xc1w\xd3.\xda;\xfa\x0fF\x22}\xc4\xd4(1u\x9e\xbc\x8d*a\xd6\xba\xdb\xb2\xc6Ug\x83'\x18\x0e]\xb1\xa2\x1aC\xc0\x11\xc3\x08\x9b\x9c\xc6\x82\x9f7\xa5S\xd7\xc0qJ\xf2\xaby<\xc5alp\xef\xe0\x17m\x7f3%V\x81\xc3\x9d\x95\xf1\xff\xb9{\x8a\xae\x81w\x0c\xd4K\x82\x1cK\xbe\xc9IE-\x9e\x01\x9e0Q\x8b\xba\xc2\xf6\xda\x03\xb4x\xf6\x99\x86\xf9\xdcP\x8b'\x84\xf1\x96\xd4\xe2y`g2\xb5\x98\x8a\xdc\xfd\x1a\x10\x04,OPu\xc9F\xf6>~\x18\xa7\xbd(G\xe4\xee\x14'\xaf\x1eJG\xee\xc6\x80\x9a\x8c\xc8\xdd\x04'6\x09z}\x85\x15\xbd.K6v5\xbeLc\x85\x17\x87-\x7fY\x86\xc7\xd5(\xd7F?\xe1T\xdf\xd1E\x9dV`\x14h\xf5y\x03\x17\xb3\xba\x1f\x10N\xec\x05\xde\xb7\x8e\xc4\xfc\x05GEa\x03\x8f\xad\xda9\x7f\xc1Q\xdcd\xe08Sa\x9b\x91p/\xc1\xc9\x1e\xae\x8f\x9df4\xd2/J\xa5\x94\xca\xf8\xef\xf8\xbc\x81?\xa5\xd2\x97\xe9\x15S7\x90\x97\xaa\xfe?\xb8b*\xc0] \xae\x98\xf2k\xc4$5\x8f\xe7\xefE\x07\x19\x9d\x9a\xbfb\x8a)\xd3\x8b\xf0`\x89+\xa6\x96T;\x9f\xb1\x03\xc2\x89J\xe0/\x0b\x5cL\xda\x86\x96\x9bK\xbe\xf3\xc0\xb3V9\xbf,\x07\x84\x13\x05\x82\x9f\xff\xa5`\xc6\xbe\x0c\x09\x01\xc7\x80\xa3\xc9\xd5\xe6\xa1\x1dHp\xa4F\x90\xab?\xce\xb1\xf1o\x03G\xb2\xbd\xb1\x7f\x98\x9f\x1ax\x84#{DD\x96\xf3S\x830\xf0!p8\x11\x1e|%\x0e$8R,\x88\xd6\xa7\x80\xf5\x821[\xf8\xb1\x87\x9c0\x80\x87\xc5\x18x\x0b\xe8\x15\x85\xa1s\x01U.W\xa4\x5c\xe6\x80\xbf\xa3\xdd)\xfa\x86\xc3\x02\xa6(\xa2\xb2\xcc\xfa\xbc\x81\xb9\x5c\xad\xf9?\xb4\xddFJx\xea]\xf1\x00\x00\x00\x00IEND\xaeB`\x82" qt_resource_name = "\x00\x12\x09\xeb\xb6g\x00i\x00c\x00o\x00n\x00_\x00i\x00n\x00s\x00t\x00a\x00l\x00l\x00e\x00d\x00.\x00p\x00n\x00g\x00\x16\x03\xa0mG\x00i\x00c\x00o\x00n\x00_\x00n\x00o\x00t\x00_\x00i\x00n\x00s\x00t\x00a\x00l\x00l\x00e\x00d\x00.\x00p\x00n\x00g\x00\x0e\x02\x0f\xe3\x87\x00i\x00c\x00o\x00n\x00_\x00a\x00b\x00o\x00u\x00t\x00.\x00p\x00n\x00g\x00\x17\x0b\xf7\xc0g\x00i\x00c\x00o\x00n\x00_\x00s\x00o\x00m\x00e\x00_\x00i\x00n\x00s\x00t\x00a\x00l\x00l\x00e\x00d\x00.\x00p\x00n\x00g\x00\x10\x08X\xa8#\x00q\x00t\x00_\x00r\x00e\x00s\x00o\x00u\x00r\x00c\x00e\x00s\x00.\x00q\x00r\x00c\x00\x0a\x03\x8f\xcf\x87\x00n\x00e\x00o\x00m\x00a\x00n\x00.\x00p\x00n\x00g" qt_resource_struct = "\x00\x00\x00\x00\x00\x02\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x02\xa9\x00\x00\x00\xd8\x00\x00\x00\x00\x00\x01\x00\x00\x07O\x00\x00\x00*\x00\x00\x00\x00\x00\x01\x00\x00\x01\xd0\x00\x00\x00\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x06j\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00\x01\x00\x00\x04\xb2" def qInitResources(): QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) def qCleanupResources(): QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) qInitResources() yubikey-neo-manager-1.4.0/neoman/__init__.py0000664000175000017500000000256212621050365020631 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. __version__ = "1.4.0" yubikey-neo-manager-1.4.0/neoman/device_otp.py0000664000175000017500000001425112620657702021220 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from neoman.ykpers import * from ctypes import byref, c_uint, c_int, c_size_t, create_string_buffer from neoman.exc import ModeSwitchError from neoman.device import BaseDevice from neoman.model.modes import MODE from neoman.yk4_utils import (parse_tlv_list, YK4_CAPA_TAG, YK4_CAPA1_OTP, YK4_CAPA1_CCID, YK4_CAPA1_U2F) if not yk_init(): raise Exception("Unable to initialize ykpers") libversion = ykpers_check_version(None) def read_version(dev): status = ykds_alloc() try: if yk_get_status(dev, status): return ( ykds_version_major(status), ykds_version_minor(status), ykds_version_build(status) ) else: return (0, 0, 0) finally: ykds_free(status) class OTPDevice(BaseDevice): device_type = 'OTP' allowed_modes = (True, False, False) def __init__(self, dev, version): self._dev = dev self._version = version ser = c_uint() if yk_get_serial(dev, 0, 0, byref(ser)): self._serial = ser.value else: self._serial = None self._mode = self._read_mode(dev) self.allowed_modes = (True, True, version >= (3, 3, 0)) def _read_mode(self, dev): vid = c_int() pid = c_int() try: yk_get_key_vid_pid(dev, byref(vid), byref(pid)) mode = 0x0f & pid.value if mode == 1: # mode 1 has PID 0112 and mode 2 has PID 0111 return 2 elif mode == 2: return 1 else: # all others have 011x where x = mode return mode except: # We know we at least have OTP enabled... return MODE.mode_for_flags(True, False, False) @property def mode(self): return self._mode @property def serial(self): return self._serial @property def version(self): return self._version def set_mode(self, mode): if self.version[0] < 3: raise ValueError("Mode Switching requires version >= 3") config = ykp_alloc_device_config() ykp_set_device_mode(config, mode) try: if not yk_write_device_config(self._dev, config): raise ModeSwitchError() finally: ykp_free_device_config(config) self._mode = mode def list_apps(self): return [] def close(self): if hasattr(self, '_dev'): yk_close_key(self._dev) del self._dev class YKStandardDevice(BaseDevice): device_type = 'OTP' supported = False serial = None version = (0, 0, 0) mode = MODE.mode_for_flags(True, False, False) def __init__(self, dev, version): self._dev = dev self._version = version @property def default_name(self): return 'YubiKey %s' % '.'.join(map(str, self._version)) def close(self): if hasattr(self, '_dev'): yk_close_key(self._dev) del self._dev class YKPlusDevice(YKStandardDevice): mode = MODE.mode_for_flags(True, False, True) default_name = 'YubiKey Plus' class YK4Device(OTPDevice): default_name = 'YubiKey 4' def __init__(self, dev, version): super(YK4Device, self).__init__(dev, version) self._read_capabilities() if self._cap == 0x07: # YK Edge should not allow CCID. self.default_name = 'YubiKey Edge' self.allowed_modes = (True, False, True) def _read_mode(self, dev): vid = c_int() pid = c_int() try: yk_get_key_vid_pid(dev, byref(vid), byref(pid)) mode = 0x0f & pid.value return MODE.mode_for_flags(bool(mode & 1), bool(mode & 4), bool(mode & 2)) except: # We know we at least have OTP enabled... return MODE.mode_for_flags(True, False, False) def _read_capabilities(self): buf_size = c_size_t(1024) resp = create_string_buffer(buf_size.value) yk_get_capabilities(self._dev, 0, 0, resp, byref(buf_size)) resp = resp.raw self._cap_data = parse_tlv_list(resp[1:ord(resp[0]) + 1]) self._cap = int(self._cap_data.get(YK4_CAPA_TAG, '0').encode('hex'), 16) self.allowed_modes = ( bool(self._cap & YK4_CAPA1_OTP), bool(self._cap & YK4_CAPA1_CCID), bool(self._cap & YK4_CAPA1_U2F) ) def open_first_device(): dev = yk_open_first_key() if not dev: raise Exception("Unable to open YubiKey NEO!") version = read_version(dev) if version >= (4, 1, 0): return YK4Device(dev, version) elif version >= (4, 0, 0): return YKPlusDevice(dev, version) elif version >= (3, 0, 0): return OTPDevice(dev, version) else: return YKStandardDevice(dev, version) yubikey-neo-manager-1.4.0/neoman/view/0000775000175000017500000000000012621055514017466 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/neoman/view/neo.py0000664000175000017500000003163412617115763020640 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import os from PySide import QtGui, QtCore from functools import partial from neoman import messages as m from neoman.storage import settings from neoman.exc import ModeSwitchError from neoman.model.neo import YubiKeyNeo from neoman.model.applet import Applet from neoman.model.modes import MODE from neoman.view.tabs import TabWidgetWithAbout U2F_URL = "http://www.yubico.com/products/yubikey-hardware/yubikey-neo/" \ + "yubikey-neo-u2f/" def get_text(*args, **kwargs): flags = ( QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowSystemMenuHint ) kwargs['flags'] = flags return QtGui.QInputDialog.getText(*args, **kwargs) class NeoPage(TabWidgetWithAbout): _neo = QtCore.Signal(YubiKeyNeo) applet = QtCore.Signal(Applet) def __init__(self): super(NeoPage, self).__init__() self._tabs = [] self._supported = True self._unsupported_tab = UnsupportedTab() settings_tab = SettingsTab() self._neo.connect(settings_tab.set_neo) self.addTab(settings_tab, m.settings) if QtCore.QCoreApplication.instance().devmode: apps = AppsTab(self, 1) self._neo.connect(apps.set_neo) apps.applet.connect(self._set_applet) self.addTab(apps, m.installed_apps) def addTab(self, tab, title): self._tabs.append((tab, title)) if self._supported: super(NeoPage, self).addTab(tab, title) @QtCore.Slot(YubiKeyNeo) def setNeo(self, neo): self._supported = neo and neo.supported self.clear() if self._supported: for (tab, title) in self._tabs: super(NeoPage, self).addTab(tab, title) else: super(NeoPage, self).addTab(self._unsupported_tab, m.settings) self._neo.emit(neo) @QtCore.Slot(Applet) def _set_applet(self, applet): self.applet.emit(applet) class UnsupportedTab(QtGui.QWidget): def __init__(self): super(UnsupportedTab, self).__init__() layout = QtGui.QVBoxLayout() layout.addWidget(QtGui.QLabel(m.unsupported_device)) self.setLayout(layout) class SettingsTab(QtGui.QWidget): def __init__(self): super(SettingsTab, self).__init__() self._neo = None self._name = QtGui.QLabel() self._serial = QtGui.QLabel() self._firmware = QtGui.QLabel() self._u2f = QtGui.QLabel() self._u2f.setOpenExternalLinks(True) layout = QtGui.QVBoxLayout() name_row = QtGui.QHBoxLayout() name_row.addWidget(self._name) self._name_btn = QtGui.QPushButton(m.change_name) self._name_btn.clicked.connect(self.change_name) name_row.addWidget(self._name_btn) details_row = QtGui.QHBoxLayout() details_row.addWidget(self._serial) details_row.addWidget(self._firmware) self._u2f_row = QtGui.QHBoxLayout() self._u2f_row.addWidget(QtGui.QLabel()) self._u2f_row.addWidget(self._u2f) layout.addLayout(name_row) layout.addLayout(details_row) layout.addLayout(self._u2f_row) button = QtGui.QPushButton(m.manage_keys) button.clicked.connect(self.manage_keys) # TODO: Re-add when implemented: # layout.addWidget(button) self._mode_btn = QtGui.QPushButton(m.change_mode) self._mode_btn.clicked.connect(self.change_mode) layout.addWidget(self._mode_btn) self._mode_note = QtGui.QLabel(m.note_1 % m.mode_note) self._mode_note.setWordWrap(True) layout.addWidget(self._mode_note) layout.addStretch() self.setLayout(layout) @QtCore.Slot(YubiKeyNeo) def set_neo(self, neo): self._neo = neo if not neo: return self._name_btn.setDisabled(neo.serial is None) self._name.setText(m.name_1 % neo.name) self._serial.setText(m.serial_1 % neo.serial) show_firmware = neo.version != (0, 0, 0) self._u2f_row.setDirection( QtGui.QBoxLayout.LeftToRight if show_firmware else QtGui.QBoxLayout.RightToLeft) self._firmware.setVisible(show_firmware) self._firmware.setText(m.firmware_1 % '.'.join(map(str, neo.version))) if neo.allowed_modes[2]: self._u2f.setText(m.u2f_1 % m.u2f_supported) else: self._u2f.setText(m.u2f_1 % m.u2f_not_supported_1 % U2F_URL) self._mode_btn.setText(m.change_mode_1 % MODE.name_for_mode(neo.mode)) self._mode_note.setVisible(neo.version < (4, 1, 0)) def change_name(self): name, ok = get_text(self, m.name, m.change_name_desc, text=self._neo.name) if ok: self._neo.name = name self._name.setText(m.name_1 % name) def manage_keys(self): print m.manage_keys def change_mode(self): mode = ModeDialog.change_mode(self._neo, self) if mode is not None: try: self._neo.set_mode(mode) except ModeSwitchError: QtGui.QMessageBox.critical(self, m.mode_error, m.mode_error_desc) return self._mode_btn.setText(m.change_mode_1 % MODE.name_for_mode(mode)) remove_dialog = QtGui.QMessageBox(self) remove_dialog.setWindowTitle(m.change_mode) remove_dialog.setIcon(QtGui.QMessageBox.Information) remove_dialog.setText(m.remove_device) remove_dialog.setStandardButtons(QtGui.QMessageBox.NoButton) self._neo.removed.connect(remove_dialog.accept) remove_dialog.exec_() class ModeDialog(QtGui.QDialog): def __init__(self, neo, parent=None): super(ModeDialog, self).__init__(parent) self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint) layout = QtGui.QVBoxLayout() layout.addWidget(QtGui.QLabel(m.change_mode_desc)) boxes = QtGui.QHBoxLayout() self._otp = QtGui.QCheckBox(m.otp) self._otp.clicked.connect(self._state_changed) boxes.addWidget(self._otp) self._ccid = QtGui.QCheckBox(m.ccid) self._ccid.clicked.connect(self._state_changed) boxes.addWidget(self._ccid) self._u2f = QtGui.QCheckBox(m.u2f) self._u2f.clicked.connect(self._state_changed) boxes.addWidget(self._u2f) layout.addLayout(boxes) buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) self._ok = buttons.button(QtGui.QDialogButtonBox.Ok) layout.addWidget(buttons) self.setWindowTitle(m.change_mode) self.setLayout(layout) allowed = neo.allowed_modes self._otp.setEnabled(allowed[0]) self._otp.setVisible(allowed[0]) self._ccid.setEnabled(allowed[1]) self._ccid.setVisible(allowed[1]) self._u2f.setEnabled(allowed[2]) self._u2f.setVisible(allowed[2]) self.mode = neo.mode def _state_changed(self): self._ok.setDisabled(not any(self.flags)) @property def flags(self): return self._otp.isChecked(), self._ccid.isChecked(), \ self._u2f.isChecked() @property def mode(self): return MODE.mode_for_flags(*self.flags) @mode.setter def mode(self, value): otp, ccid, u2f, touch_eject = MODE.flags_for_mode(value) self._otp.setChecked(otp and self._otp.isEnabled()) self._ccid.setChecked(ccid and self._ccid.isEnabled()) self._u2f.setChecked(u2f and self._u2f.isEnabled()) @classmethod def change_mode(cls, neo, parent=None): dialog = cls(neo, parent) if dialog.exec_(): mode = dialog.mode legacy = neo.version < (3, 3, 0) if legacy and mode == 2: # Always set 82 instead of 2 mode = 0x82 return mode else: return None class AppsTab(QtGui.QWidget): applet = QtCore.Signal(Applet) def __init__(self, parent, index): super(AppsTab, self).__init__() self.parent = parent self.index = index layout = QtGui.QVBoxLayout() self._apps = [] self._apps_list = QtGui.QListView() self._apps_list.setModel(QtGui.QStringListModel([])) self._apps_list.setEditTriggers(QtGui.QListView.NoEditTriggers) self._apps_list.doubleClicked.connect(self.open_app) layout.addWidget(self._apps_list) self._install_cap_btn = QtGui.QPushButton(m.install_cap) self._install_cap_btn.clicked.connect(self.install_cap) layout.addWidget(self._install_cap_btn) layout.addStretch() self.setLayout(layout) parent.currentChanged.connect(self.tab_changed) def install_cap(self): path = settings.value('filepicker/path', None) (cap, _) = QtGui.QFileDialog.getOpenFileName(self, m.select_cap, path, "*.cap") if not cap: return settings.setValue('filepicker/path', os.path.dirname(cap)) worker = QtCore.QCoreApplication.instance().worker self._cap = os.path.basename(cap) worker.post(m.installing, partial(self._neo.install_app, cap), self.install_done) @QtCore.Slot(object) def install_done(self, status): if status: print status QtGui.QMessageBox.warning(self, m.error_installing, m.error_installing_1 % self._cap) self.set_neo(self._neo) def open_app(self, index): readable = index.data() aid = readable[readable.rindex('(') + 1:readable.rindex(')')] appletmanager = QtCore.QCoreApplication.instance().appletmanager self.applet.emit(appletmanager.get_applet(aid)) def tab_changed(self, index): if index != self.index: return try: while self._neo.locked: try: self._neo.unlock() except Exception as e: del self._neo.key print e pw, ok = get_text(self, m.key_required, m.key_required_desc) if not ok: self.parent.setCurrentIndex(0) return self._neo.key = pw appletmanager = QtCore.QCoreApplication.instance().appletmanager self._apps = filter(None, map(appletmanager.get_applet, self._neo.list_apps())) self._apps_list.model().setStringList( map(lambda app: "%s (%s)" % (app.name, app.aid), self._apps)) except AttributeError: pass @QtCore.Slot(YubiKeyNeo) def set_neo(self, neo): self._neo = neo if not neo or not neo.has_ccid: self.parent.setTabEnabled(self.index, False) self.parent.setTabToolTip(self.index, m.requires_ccid) return self.parent.setTabEnabled(self.index, True) self.parent.setTabToolTip(self.index, None) if neo.locked: try: neo.unlock() except: return appletmanager = QtCore.QCoreApplication.instance().appletmanager self._apps = filter(None, map(appletmanager.get_applet, neo.list_apps())) self._apps_list.model().setStringList( map(lambda app: "%s (%s)" % (app.name, app.aid), self._apps)) yubikey-neo-manager-1.4.0/neoman/view/__init__.py0000664000175000017500000000253312233476037021610 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. yubikey-neo-manager-1.4.0/neoman/view/tabs.py0000664000175000017500000000472612617115763021012 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtGui from neoman import __version__ as version, messages as m from neoman.device_ccid import libversion as ykneomgr_version from neoman.device_otp import libversion as ykpers_version from neoman.device_u2f import libversion as u2fh_version FORUM_URL = "http://yubi.co/forum" ABOUT_TEXT = """

%s

%s
%s

%s

%%s

%s """ % (m.app_name, m.copyright, m.version_1, m.libraries, m.about_link_1 % FORUM_URL) class TabWidgetWithAbout(QtGui.QTabWidget): def __init__(self): super(TabWidgetWithAbout, self).__init__() btn = QtGui.QToolButton() icon = QtGui.QIcon(':/icon_about.png') btn.setIcon(icon) btn.clicked.connect(self._about) self.setCornerWidget(btn) def _libversions(self): libs = ['libykneomgr: ' + ykneomgr_version, 'ykpers: ' + ykpers_version, 'libu2f-host: ' + u2fh_version] return '
'.join(libs) def _about(self): QtGui.QMessageBox.about( self, m.about_1 % m.app_name, ABOUT_TEXT % (version, self._libversions()) ) yubikey-neo-manager-1.4.0/neoman/view/welcome.py0000664000175000017500000000337112617115763021507 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtGui from neoman import messages as m from neoman.view.tabs import TabWidgetWithAbout class WelcomePage(TabWidgetWithAbout): def __init__(self): super(WelcomePage, self).__init__() layout = QtGui.QVBoxLayout() layout.addWidget(QtGui.QLabel(m.welcome_desc)) widget = QtGui.QWidget() widget.setLayout(layout) self.addTab(widget, m.welcome) yubikey-neo-manager-1.4.0/neoman/view/nav.py0000664000175000017500000002013012471132571020622 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtGui, QtCore from neoman.model.neo import YubiKeyNeo from neoman.model.applet import Applet from neoman import messages as m class NavTree(QtGui.QTreeView): subpage = QtCore.Signal(object) def __init__(self): super(NavTree, self).__init__() self.setHeaderHidden(True) self.setModel(NavModel()) self.expandAll() self.current = None self.model().rowsInserted.connect(self._data_changed) self._data_changed() @QtCore.Slot(YubiKeyNeo) @QtCore.Slot(Applet) def setCurrent(self, current): self.current = current try: if isinstance(current, YubiKeyNeo): neo_index = self.model().neo_list.index(current) self.setCurrentIndex( self.model().index( neo_index, 0, self.model().categories[m.devices])) elif isinstance(current, Applet): applet_index = self.model().applets.index(current) self.setCurrentIndex( self.model().index( applet_index, 0, self.model().categories[m.apps])) except: self.clearSelection() def setCurrentIndex(self, index): super(NavTree, self).setCurrentIndex(index) self.model().refresh_icons(index) def currentChanged(self, current, previous): if current.flags() & QtCore.Qt.ItemIsSelectable: self.current = current.internalPointer() self.subpage.emit(self.current) elif not self.model().neo_list: self.current = None self.subpage.emit(None) elif isinstance(self.current, YubiKeyNeo): pass else: self.current = self.model().neo_list[0] self.subpage.emit(self.current) def _data_changed(self): if not self.current and self.model().neo_list: self.setCurrentIndex( self.model().index(0, 0, self.model().categories[m.devices])) elif isinstance(self.current, YubiKeyNeo) \ and self.current not in self.model().neo_list: self.current = None self.subpage.emit(None) class NavModel(QtCore.QAbstractItemModel): def __init__(self): super(NavModel, self).__init__() self.categories = { m.devices: self.createIndex(0, 0, m.devices), m.apps: self.createIndex(1, 0, m.apps) } self.refresh_icons() self.applets = [] available = QtCore.QCoreApplication.instance().available_neos available.changed.connect(self.data_changed) self.neo_list = available.get() self._update_applets() def refresh_icons(self, index=None): if index and index.isValid(): self._get_icon(index, True) else: self._icons = {m.devices: {}, m.apps: {}} @QtCore.Slot(list) def data_changed(self, new_neos): parent = self.categories[m.devices] self.beginRemoveRows(parent, 0, self.rowCount(parent) - 1) self.neo_list = [] self.endRemoveRows() self.beginInsertRows(parent, 0, len(new_neos) - 1) self.neo_list = new_neos self.endInsertRows() self._update_applets() self.refresh_icons() def _update_applets(self): parent = self.categories[m.apps] self.beginRemoveRows(parent, 0, self.rowCount(parent) - 1) self.applets = [] self.endRemoveRows() new_applets = [] installed = {app for neo in self.neo_list for app in neo.list_apps()} appletmanager = QtCore.QCoreApplication.instance().appletmanager if QtCore.QCoreApplication.instance().devmode: new_applets = appletmanager.get_applets() else: for applet in appletmanager.get_applets(): if any([aid.startswith(applet.aid) for aid in installed]): new_applets.append(applet) self.beginInsertRows(parent, 0, len(new_applets) - 1) self.applets = new_applets self.endInsertRows() def index(self, row, column, parent=QtCore.QModelIndex()): if not parent.isValid(): node = m.devices if row == 0 else m.apps return self.categories[node] category = parent.internalPointer() if category == m.devices: return self.createIndex(row, column, self.neo_list[row]) return self.createIndex(row, column, self.applets[row]) def parent(self, index): if not index.isValid(): return QtCore.QModelIndex() node = index.internalPointer() if node in self.categories: return QtCore.QModelIndex() if isinstance(node, YubiKeyNeo): return self.categories[m.devices] return self.categories[m.apps] def columnCount(self, parent=QtCore.QModelIndex()): return 1 def rowCount(self, parent=QtCore.QModelIndex()): if not parent.isValid(): return 2 node = parent.internalPointer() if node in self.categories: return len(self.neo_list if node == m.devices else self.applets) return 0 def data(self, index, role=QtCore.Qt.DisplayRole): if index.isValid(): if role == QtCore.Qt.DisplayRole: return str(index.internalPointer()) elif QtCore.QCoreApplication.instance().devmode and \ role == QtCore.Qt.DecorationRole: return self._get_icon(index) def _get_icon(self, index, force_refresh=False): parent = index.parent() if not parent.isValid(): return None category = parent.internalPointer() if force_refresh or index.row() not in self._icons[category]: self._icons[category][index.row()] = self._build_icon(index) return self._icons[category][index.row()] def _build_icon(self, index): item = index.internalPointer() icon_template = ':/icon_%s.png' if isinstance(item, Applet): all_installed = bool(self.neo_list) some_installed = False for neo in self.neo_list: if any((aid.startswith(item.aid) for aid in neo.list_apps())): some_installed = True else: all_installed = False if all_installed: return QtGui.QPixmap(icon_template % 'installed') elif some_installed: return QtGui.QPixmap(icon_template % 'some_installed') else: return QtGui.QPixmap(icon_template % 'not_installed') def flags(self, index): node = index.internalPointer() if node in self.categories: return QtCore.Qt.ItemIsEnabled return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled yubikey-neo-manager-1.4.0/neoman/view/main.py0000664000175000017500000001034612617115763021000 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtGui from PySide import QtCore from neoman.model.neo import YubiKeyNeo from neoman.model.applet import Applet from neoman.view.nav import NavTree from neoman.view.welcome import WelcomePage from neoman.view.neo import NeoPage from neoman.view.applet import AppletPage from neoman.storage import settings from PySide.QtGui import QSizePolicy class CentralWidget(QtGui.QWidget): def __init__(self): super(CentralWidget, self).__init__() self.build_ui() self.resize(settings.value('window/size', QtCore.QSize(0, 0))) def build_ui(self): layout = QtGui.QHBoxLayout(self) layout.addWidget(self.build_nav()) layout.addWidget(self.build_main()) self._nav.subpage.connect(self._main.setContent) self._main.setContent(self._nav.current) self._main.current.connect(self._nav.setCurrent) def build_nav(self): layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self._nav = NavTree() layout.addWidget(self._nav) widget = QtGui.QWidget() widget.setLayout(layout) widget.setMaximumWidth(200) widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) return widget def build_main(self): self._main = ContentWidget() return self._main def closeEvent(self, event): settings.setValue('window/size', self.size()) event.accept() class ContentWidget(QtGui.QStackedWidget): current = QtCore.Signal(object) _neo = QtCore.Signal(YubiKeyNeo) _applet = QtCore.Signal(Applet) def __init__(self): super(ContentWidget, self).__init__() self._content = None self._start_page = WelcomePage() self.addWidget(self._start_page) self._neo_page = NeoPage() self._neo_page.applet.connect(self.setContent) self._neo.connect(self._neo_page.setNeo) self.addWidget(self._neo_page) self._app_page = AppletPage() self._app_page.applet_status.connect(self.setContent) self._neo.connect(self._app_page.setNeo) self._applet.connect(self._app_page.setApplet) self.addWidget(self._app_page) self.setMinimumSize(420, 240) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) @QtCore.Slot(YubiKeyNeo) @QtCore.Slot(Applet) def setContent(self, content): self._content = content if content is None: self._neo.emit(None) self._applet.emit(None) self.setCurrentWidget(self._start_page) elif isinstance(content, YubiKeyNeo): self._neo.emit(content) self.setCurrentWidget(self._neo_page) elif isinstance(content, Applet): self._applet.emit(content) self.setCurrentWidget(self._app_page) self.current.emit(content) yubikey-neo-manager-1.4.0/neoman/view/applet.py0000664000175000017500000002066112620661202021326 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtGui, QtCore from neoman.model.applet import Applet from neoman.model.neo import YubiKeyNeo from neoman.storage import capstore from neoman.view.tabs import TabWidgetWithAbout from neoman import messages as m from functools import partial class AppletPage(TabWidgetWithAbout): applet_status = QtCore.Signal(Applet) _applet = QtCore.Signal(Applet) _neo = QtCore.Signal(YubiKeyNeo) def __init__(self): super(AppletPage, self).__init__() overview = OverviewTab() overview.install_status.connect(self._install_status_changed) self._applet.connect(overview.set_applet) self._neo.connect(overview.set_neo) self.addTab(overview, m.overview) def _install_status_changed(self, applet, installed): self.applet_status.emit(applet) @QtCore.Slot(Applet) def setApplet(self, applet): self._applet.emit(applet) @QtCore.Slot(YubiKeyNeo) def setNeo(self, neo): self._neo.emit(neo) class OverviewTab(QtGui.QWidget): install_status = QtCore.Signal(Applet, bool) def __init__(self): super(OverviewTab, self).__init__() self._applet = None self._neo = None self._name = QtGui.QLabel() self._description = QtGui.QLabel() self._status = QtGui.QLabel() self._aid = QtGui.QLabel() self._latest_version = QtGui.QLabel() available = QtCore.QCoreApplication.instance().available_neos available.changed.connect(self.data_changed) self._neo_selector = QtGui.QComboBox() self._neo_selector.activated.connect(self.neo_selected) for neo in available.get(): self._neo_selector.addItem(neo.name, neo) self._install_button = QtGui.QPushButton() self._install_button.clicked.connect(self.install_button_click) header = QtGui.QHBoxLayout() col_1 = QtGui.QVBoxLayout() col_2 = QtGui.QVBoxLayout() col_1.addWidget(self._name) col_1.addWidget(self._status) #col_1.addWidget(self._aid) col_2.addWidget(self._neo_selector) if QtCore.QCoreApplication.instance().devmode: col_1.addWidget(self._latest_version) col_2.addWidget(self._install_button) header.addLayout(col_1) header.addLayout(col_2) layout = QtGui.QVBoxLayout() layout.addLayout(header) separator = QtGui.QFrame() separator.setFrameStyle(QtGui.QFrame.HLine | QtGui.QFrame.Sunken) layout.addWidget(separator) layout.addWidget(self._description) layout.addStretch() self.setLayout(layout) def install_button_click(self): installed = self._neo and any( [x.startswith(self._applet.aid) for x in self._neo.list_apps()]) worker = QtCore.QCoreApplication.instance().worker if installed: # Uninstall if QtGui.QMessageBox.Ok != QtGui.QMessageBox.warning( self, m.delete_app_confirm, m.delete_app_desc, QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel): return work = partial(self._neo.delete_app, self._applet.aid) worker.post(m.deleting_1 % self._applet.name, work, self._cb_uninstall) elif self._applet.is_downloaded: # Install work = partial(self._neo.install_app, self._applet.cap_file) worker.post(m.installing_1 % self._applet.name, work, self._cb_install) else: # Download and install worker.download(self._applet.cap_url, self._cb_download) @QtCore.Slot(object) def _cb_install(self, result): if result: msg = m.error_installing_1 % self._applet.name msg += '\n%s' % result QtGui.QMessageBox.warning(self, m.error_installing, msg) self.install_status.emit(self._applet, True) self.neo_or_applet_changed(self._neo, self._applet) @QtCore.Slot(object) def _cb_uninstall(self, result): if result: msg = m.error_uninstalling_1 % self._applet.name msg += '\n%s' % result QtGui.QMessageBox.warning(self, m.error_uninstalling, msg) self.install_status.emit(self._applet, False) self.neo_or_applet_changed(self._neo, self._applet) @QtCore.Slot(object) def _cb_download(self, result): if isinstance(result, QtCore.QByteArray): capstore.store_data(self._applet.aid, self._applet.latest_version, result, self._applet.cap_sha1) self.install_button_click() # Now install else: msg = m.error_downloading_1 % self._applet.name msg += '\n%s' % result QtGui.QMessageBox.warning(self, m.error_downloading, msg) @QtCore.Slot(Applet) def set_applet(self, applet): if applet: self._applet = applet self._name.setText(m.name_1 % applet.name) self._aid.setText(m.aid_1 % applet.aid) self._latest_version.setText( m.latest_version_1 % (applet.latest_version or m.unknown)) self._description.setText(applet.description) self.neo_or_applet_changed(self._neo, applet) @QtCore.Slot(YubiKeyNeo) def set_neo(self, neo): if neo and neo.has_ccid: self._neo = neo self._neo_selector.setCurrentIndex( self._neo_selector.findData(neo)) self.neo_or_applet_changed(neo, self._applet) def neo_or_applet_changed(self, neo, applet): if not applet: return installed, version = applet.get_status(neo) if neo else (False, None) if installed: if version: self._status.setText(m.status_1 % (m.installed_1 % version)) else: self._status.setText(m.status_1 % m.installed) else: self._status.setText(m.status_1 % m.not_installed) if installed: enabled = applet.allow_uninstall elif applet.is_downloaded: enabled = bool(neo) else: enabled = bool(neo and applet.cap_url) self._install_button.setText(m.uninstall if installed else m.install) self._install_button.setEnabled(enabled) if neo and self._neo_selector.currentText() != neo.name: self._neo_selector.setItemText(self._neo_selector.currentIndex(), neo.name) @QtCore.Slot(int) def neo_selected(self, index): self.set_neo(self._neo_selector.itemData(index)) @QtCore.Slot(list) def data_changed(self, new_neos): self._neo_selector.clear() new_neos = [neo for neo in new_neos if neo.has_ccid] for neo in new_neos: self._neo_selector.addItem(neo.name, neo) if self._neo in new_neos: self._neo_selector.setCurrentIndex(new_neos.index(self._neo)) else: self._neo = None if not new_neos else new_neos[0] self.neo_or_applet_changed(self._neo, self._applet) # class SettingsTab # - Manage app specific settings against NEOs which have it installed. yubikey-neo-manager-1.4.0/neoman/storage.py0000644000175000017500000000625612314266655020552 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import os from PySide import QtCore from hashlib import sha1 __all__ = [ 'CONFIG_HOME', 'settings', 'capstore' ] CONFIG_HOME = os.path.join(os.path.expanduser('~'), '.neoman') settings = QtCore.QSettings(os.path.join(CONFIG_HOME, 'settings.ini'), QtCore.QSettings.IniFormat) class AppletCapStore(object): def __init__(self, basedir): self._dir = basedir def _build_fname(self, aid, version): return os.path.join(self._dir, aid, '%s.cap' % version) def _validate_hash(self, fname, cap_sha1): with open(fname, 'rb') as cap: return sha1(cap.read()).hexdigest() == cap_sha1 def has_file(self, aid, version, cap_sha1=None): fname = self._build_fname(aid, version) if os.path.isfile(fname): if cap_sha1 and not self._validate_hash(fname, cap_sha1): return False return True return False def get_filename(self, aid, version, cap_sha1=None): fname = self._build_fname(aid, version) if not self.has_file(aid, version): raise ValueError("File not found: %s" % fname) if cap_sha1 and not self._validate_hash(fname, cap_sha1): raise ValueError("Incorrect SHA1 hash!") return fname def store_data(self, aid, version, data, cap_sha1=None): fname = self._build_fname(aid, version) QtCore.QDir.root().mkpath(os.path.dirname(fname)) target = QtCore.QFile(fname) target.open(QtCore.QIODevice.WriteOnly) if target.write(data) == -1: raise ValueError("Unable to write data!") target.close() if cap_sha1 and not self._validate_hash(fname, cap_sha1): target.remove() raise ValueError("Incorrect SHA1 hash!") capstore = AppletCapStore(os.path.join(CONFIG_HOME, 'applets')) yubikey-neo-manager-1.4.0/neoman/model/0000775000175000017500000000000012621055514017614 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/neoman/model/neo.py0000664000175000017500000001671312617115763020767 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtCore, QtGui from neoman.device import open_all_devices, ResetStateException from neoman.storage import settings from functools import wraps DEFAULT_KEY = "404142434445464748494a4b4c4d4e4f" def with_mutex(mutex, func): @wraps(func) def inner(*args, **kwargs): try: mutex.lock() return func(*args, **kwargs) finally: mutex.unlock() return inner class YubiKeyNeo(QtCore.QObject): removed = QtCore.Signal() def __init__(self, device): super(YubiKeyNeo, self).__init__() self._mutex = QtCore.QMutex(QtCore.QMutex.Recursive) self._serial = device.serial self._version = device.version self._apps = None self._group = self._serial if self._serial else "NOSERIAL" self._set_device(device) def _set_device(self, device): if self.serial != device.serial or self.version != device.version: print self.serial, self.version, device.serial, device.version raise ValueError("New device must have same serial/version.") self._dev = device self._mode = device.mode self._default_name = device.default_name # self._apps = None if device.has_ccid: device.key = self.key.decode('hex') def __setitem__(self, key, value): settings.setValue('%s/%s' % (self._group, key), value) def __delitem__(self, key): settings.remove('%s/%s' % (self._group, key)) def __getitem__(self, key): return self.get(key) def __nonzero__(self): return True def __len__(self): try: settings.beginGroup('%s' % self._group) return len(settings.allKeys()) finally: settings.endGroup() def __getattr__(self, name): try: self._mutex.lock() if not self._dev: raise AttributeError(name) attr = getattr(self._dev, name) if hasattr(attr, '__call__'): attr = with_mutex(self._mutex, attr) return attr finally: self._mutex.unlock() def __delattr__(self, key): del self[key] def get(self, key, default=None): return settings.value('%s/%s' % (self._group, key), default) @property def name(self): return self.get('name', self._default_name) @name.setter def name(self, new_name): self['name'] = new_name @property def key(self): return self.get('key', DEFAULT_KEY) @key.setter def key(self, new_key): self['key'] = new_key try: self._mutex.lock() self._dev.key = new_key.decode('hex') finally: self._mutex.unlock() def set_key(self, new_key): try: self._mutex.lock() print "NOT IMPLEMENTED" # TODO: change key finally: self._mutex.unlock() @property def has_ccid(self): try: self._mutex.lock() return self._dev and self._dev.has_ccid finally: self._mutex.unlock() @property def mode(self): return self._mode @property def serial(self): return self._serial @property def version(self): return self._version def __str__(self): return self.name def list_apps(self): try: self._mutex.lock() if self.device_type != 'CCID': return [] if self._apps is None: apps = [] appletmanager = QtCore.QCoreApplication.instance() \ .appletmanager for applet in appletmanager.get_applets(): installed, version = applet.get_status(self) if installed: apps.append(applet.aid) self._apps = apps return self._apps finally: self._mutex.unlock() class AvailableNeos(QtCore.QThread): changed = QtCore.Signal(list) def __init__(self): super(AvailableNeos, self).__init__() self._mutex = QtCore.QMutex() self._neos = [] self._running = True self._sleep = 1000 def stop(self): self._running = False self.wait() def get(self): try: self._mutex.lock() return self._neos[:] finally: self._mutex.unlock() def run(self): self.discover_devices() # Discover initial devices. while self._running: if QtGui.QApplication.activeWindow(): # Only if we have focus self.discover_devices() self.msleep(self._sleep) def discover_devices(self): neos = self.get() existing_devs = [] for neo in neos: if neo._dev: neo._mutex.lock() existing_devs.append(neo._dev) neo._dev = None new_neos = [] dead_neos = neos[:] state_reset = False # Set True after state reset try: discovered = open_all_devices(existing_devs) if self._sleep > 1000: # State reset! self._sleep = 1000 # Reset sleep time state_reset = True except ResetStateException as e: discovered = e.devices self._sleep = 3500 # Increase sleep time for dev in discovered: for neo in dead_neos[:]: if dev.serial == neo.serial and dev.version == neo.version \ and dev.device_type == dev.device_type: neo._set_device(dev) neo._mutex.unlock() dead_neos.remove(neo) break else: new_neos.append(YubiKeyNeo(dev)) for neo in dead_neos: neos.remove(neo) neo.removed.emit() neo._mutex.unlock() if new_neos or dead_neos or state_reset: self._mutex.lock() self._neos = neos + new_neos neos_copy = self._neos[:] self._mutex.unlock() self.changed.emit(neos_copy) yubikey-neo-manager-1.4.0/neoman/model/__init__.py0000664000175000017500000000253312233476030021727 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. yubikey-neo-manager-1.4.0/neoman/model/jsapi.py0000664000175000017500000000507512423430225021277 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtCore, QtWebKit import os class AppletNotInstalledException(Exception): pass class JS_API(QtCore.QObject): def __init__(self, neo, applet): super(JS_API, self).__init__() self._neo = neo self._applet = applet self._webpage = QtWebKit.QWebPage() self._frame = self._webpage.mainFrame() self._frame.addToJavaScriptWindowObject('_JS_API', self) def __enter__(self): basedir = QtCore.QCoreApplication.instance().basedir path = os.path.join(basedir, 'js_api.js') with open(path, 'r') as f: if not self._frame.evaluateJavaScript(f.read()): del self._frame raise AppletNotInstalledException() return self def __exit__(self, type, value, traceback): del self._frame def run(self, script): return self._frame.evaluateJavaScript(script) @QtCore.Slot(str) def log(self, line): print "LOG [%s]: %s" % (self._applet.name, line) @QtCore.Slot(str, result=str) def send_apdu(self, apdu): return self._neo.send_apdu(apdu.decode('hex')).encode('hex') def _aid(self): return self._applet.aid aid = QtCore.Property(unicode, _aid) yubikey-neo-manager-1.4.0/neoman/model/modes.py0000664000175000017500000000214212401552504021271 0ustar daindain00000000000000from neoman import messages as m class Modes(object): # OTP, CCID, U2F MODE_CODES = { (True, False, False): 0x00, (False, True, False): 0x01, (True, True, False): 0x02, (False, False, True): 0x03, (True, False, True): 0x04, (False, True, True): 0x05, (True, True, True): 0x06 } TOUCH_EJECT_FLAG = 0x80 MODE_NAMES = [ m.otp, m.ccid, m.otp_ccid, m.u2f, m.otp_u2f, m.u2f_ccid, m.otp_u2f_ccid ] def name_for_mode(self, mode): return self.MODE_NAMES[mode & ~self.TOUCH_EJECT_FLAG] def mode_for_flags(self, otp, ccid, u2f, touch_eject=False): mode = self.MODE_CODES[(otp, ccid, u2f)] if touch_eject: mode |= self.TOUCH_EJECT_FLAG return mode def flags_for_mode(self, mode): touch_eject = mode & self.TOUCH_EJECT_FLAG != 0 mode &= ~self.TOUCH_EJECT_FLAG for (otp, ccid, u2f), code in self.MODE_CODES.items(): if code == mode: return otp, ccid, u2f, touch_eject MODE = Modes() yubikey-neo-manager-1.4.0/neoman/model/applet.py0000664000175000017500000001171012565113112021447 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtCore, QtNetwork from Crypto.Signature import PKCS1_PSS from Crypto.Hash import SHA256 from Crypto.PublicKey import RSA from neoman.model.jsapi import JS_API, AppletNotInstalledException from neoman.networker import NetWorker from neoman.storage import CONFIG_HOME, capstore from neoman import messages as m import os import json __all__ = ['Applet', 'AppletManager'] DB_FILE = os.path.join(CONFIG_HOME, "appletdb.json") class Applet(object): def __init__(self, aid, name, description, **kwargs): self.aid = aid self.name = name self.description = description self.latest_version = kwargs.get('version', 'unknown') self.cap_url = kwargs.get('cap_url', None) self.cap_sha1 = kwargs.get('cap_sha1', None) self.allow_uninstall = kwargs.get('allow_uninstall', True) self._js_version = kwargs.get('js_version', None) self.tabs = kwargs.get('tabs', {}) def __str__(self): return self.name @property def is_downloaded(self): return capstore.has_file(self.aid, self.latest_version) @property def cap_file(self): return capstore.get_filename(self.aid, self.latest_version, self.cap_sha1) def get_status(self, neo): installed = False version = None try: with JS_API(neo, self) as api: installed = True if self._js_version: version = api.run(self._js_version) except AppletNotInstalledException: pass return (installed, version) class AppletManager(object): def __init__(self): self._hidden = [] self._applets = [] self._read_db() self.networker = NetWorker(QtCore.QCoreApplication.instance().worker) def update(self): self.networker.download_bg(self._db_url, self._updated) def _updated(self, data): if not isinstance(data, QtNetwork.QNetworkReply.NetworkError): try: data = json.loads(data.data()) data = self._verify(**data) with open(DB_FILE, 'w') as db: json.dump(data, db) if data['location'] != self._db_url: self._db_url = data['location'] self.update() else: self._read_db() except: pass # Ignore def _verify(self, message, signature): key = RSA.importKey(self._pub_key) h = SHA256.new() h.update(message) verifier = PKCS1_PSS.new(key) if verifier.verify(h, signature.decode('base64')): return json.loads(message.decode('base64')) raise ValueError("Invalid file signature!") def _read_db(self): try: with open(DB_FILE, 'r') as db: data = json.load(db) except: basedir = QtCore.QCoreApplication.instance().basedir path = os.path.join(basedir, 'appletdb.json') with open(path, 'r') as db: data = json.load(db) self._applets = [] for applet in data['applets']: self._applets.append(Applet(**applet)) self._hidden = data['hidden'] self._db_url = data['location'] self._pub_key = data['pubkey'] def get_applets(self): return self._applets def get_applet(self, aid): if aid in self._hidden: return None for applet in self._applets: if aid.startswith(applet.aid): return applet return Applet(aid, m.unknown, m.unknown_applet) yubikey-neo-manager-1.4.0/neoman/appletdb.json0000664000175000017500000000431512617115763021215 0ustar daindain00000000000000{ "location": "https://developers.yubico.com/neo_app_db_signed.json", "pubkey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArM0ylYcaT84KDgwYlazg\n+kzZo/vsDYHflq+go9Jk8EE9BMeGmvpKdwCS7+jeEcmc7MhQeK7cZ4Av7QsywL8I\nGDESG6PPQypebaw3JqQBm6zzrUwDPoI6488pJ2Hsx+N+d3wPGwEShTa+CVxnaY83\nJs1Rrz6G52HmJRSO0dIFZIadm4wUmXRFO8eFyKnySREOiL6hVYduo5wuwiZXRl/P\njDnePmREaLOJjsVbUyL3Kc9lxeBZzCV7zIvyLwBfjkFdDADMdR/F54iJTeYsmEbw\n3T5gRqzGnc1se/0x+CVMowMLRb41t47MFJzP92K/ub0Cg15uzz1JKjuvJA/6r2fJ\nYwIDAQAB\n-----END PUBLIC KEY-----", "hidden": [ "a0000000035350", "a000000527300101", "d2760000850101" ], "applets": [ { "name": "YubiKey OTP", "description": "YubiKey One-Time Passwords.", "aid": "a0000005272001", "allow_uninstall": false, "js_version": "Neo.select.slice(0,3).join('.')" }, { "name": "YubiOATH", "description": "YubiKey OATH applet for Yubico Authenticator.", "aid": "a0000005272101", "version": "0.2.1", "cap_url": "https://developers.yubico.com/ykneo-oath/Releases/ykneo-oath-0.2.1.cap", "cap_sha1": "56e599f48ed5dcf28e370c14c118ec2db3b3e10f", "js_version": "Neo.select.slice(2,5).join('.')" }, { "name": "Yubico U2F", "description": "FIDO U2F for YubiKey.", "aid": "a0000005271002", "js_version": "Neo.select.slice(0,3).join('.')" }, { "name": "Yubico U2F", "description": "FIDO U2F for YubiKey.", "aid": "a0000006472f0001", "js_version": "Neo.send_ok('00420000').slice(0,3).join('.')" }, { "name": "OpenPGP", "description": "OpenPGP applet for use with the GNU Privacy Guard.", "aid": "d27600012401", "version": "1.0.10", "cap_url": "https://developers.yubico.com/ykneo-openpgp/Releases/ykneo-openpgp-1.0.10.cap", "cap_sha1": "59c71d80080fa41e38787adc8d7ba086f9a0a93c", "js_version": "Neo.send_ok('00f10000').slice(0,3).map(function(x){return x.toString(16)}).join('.')" }, { "name": "Yubico PIV", "description": "The YubiKey PIV applet implements NIST SP800-73-3.", "aid": "a000000308", "allow_uninstall": false, "js_version": "Neo.send_ok('00fd0000').slice(0,3).join('.')" } ] } yubikey-neo-manager-1.4.0/neoman/device.py0000664000175000017500000000753512617115763020347 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from neoman.model.modes import MODE class BaseDevice(object): @property def default_name(self): return 'YubiKey NEO' @property def supported(self): return True @property def device_type(self): raise NotImplementedError() @property def mode(self): raise NotImplementedError() @property def allowed_modes(self): return (False, False, False) @property def has_ccid(self): return MODE.flags_for_mode(self.mode)[1] @property def serial(self): raise NotImplementedError() @property def version(self): raise NotImplementedError() def __del__(self): if hasattr(self, 'close'): self.close() def __str__(self): return "NEO[mode=%x, serial=%s]" % (self.mode, self.serial) class ResetStateException(Exception): def __init__(self, devs): self.devices = devs def open_all_devices(existing=None): devices = [] # CCID devices try: from neoman.device_ccid import open_all_devices as open_ccid_all for dev in open_ccid_all(existing): devices.append(dev) except Exception: pass # OTP devices (only if no CCIDs were found) if not devices: dev = None try: from neoman.device_otp import (OTPDevice, open_first_device as open_otp) # Close any existing OTP devices as we are going to reopen them. for e_dev in existing: if isinstance(e_dev, OTPDevice): e_dev.close() dev = open_otp() devices.append(dev) except Exception: pass if dev and dev.has_ccid: print "OTP device with CCID, sleep..." # This key should have been picked up as CCID device, # Make sure it gets a change to next time raise ResetStateException(devices) # U2F devices (No CCIDs nor OTPs) if not devices: u2f_devs = [] try: from neoman.device_u2f import open_all_devices as open_u2f_all u2f_devs = open_u2f_all() devices.extend(u2f_devs) except Exception: pass if filter(lambda x: x.has_ccid, u2f_devs): print "U2F device with CCID, sleep..." # This key should have been picked up as CCID device, # Make sure it gets a change to next time raise ResetStateException(devices) return devices yubikey-neo-manager-1.4.0/neoman/__main__.py0000664000175000017500000000637712565113112020617 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. import sys import time import argparse import signal import neoman.qt_resources from PySide import QtGui, QtCore from neoman.view.main import CentralWidget from neoman.model.neo import AvailableNeos from neoman.model.applet import AppletManager from neoman import __version__ as version, messages as m from neoman.yubicommon import qt class NeomanApplication(qt.Application): def __init__(self, argv): super(NeomanApplication, self).__init__(m) QtCore.QCoreApplication.setOrganizationName(m.organization) QtCore.QCoreApplication.setOrganizationDomain(m.domain) QtCore.QCoreApplication.setApplicationName(m.app_name) args = self._parse_args() self.devmode = args.devmode self.available_neos = AvailableNeos() self.available_neos.start() self.aboutToQuit.connect(self.available_neos.stop) self.appletmanager = AppletManager() self._init_window() self.appletmanager.update() def _parse_args(self): parser = argparse.ArgumentParser(description="YubiKey NEO Manager", add_help=True) parser.add_argument('-d', '--devmode', action='store_true', default=False, help='enables features which ' 'require the transport keys of the device to be ' 'known') return parser.parse_args() def _init_window(self): self.window.setWindowTitle(m.win_title_1 % version) self.window.setWindowIcon(QtGui.QIcon(':/neoman.png')) self.window.setCentralWidget(CentralWidget()) self.window.show() self.window.raise_() def main(): signal.signal(signal.SIGINT, signal.SIG_DFL) app = NeomanApplication(sys.argv) status = app.exec_() app.worker.thread().quit() app.deleteLater() time.sleep(0.01) sys.exit(status) if __name__ == '__main__': main()yubikey-neo-manager-1.4.0/neoman/js_api.js0000644000175000017500000000243612401345501020314 0ustar daindain00000000000000Neo = {}; (function(){ //Internal function bytes_to_hex(bytes) { var hex = ""; for(var i=0; inot supported" aid_1 = "AID: %s" status_1 = "Status: %s" version_1 = "Version: %s" latest_version_1 = "Latest version: %s" download = "Download" downloading_file = "Downloading file..." install = "Install" installed = "Installed" installed_1 = "%s installed" installing = "Installing applet" installing_1 = "Installing applet: %s" error_installing = "Error installing applet" error_installing_1 = "There was an error installing the applet: %s" error_uninstalling = "Error uninstalling applet" error_uninstalling_1 = "There was an error uninstalling the applet: %s" error_downloading = "Error downloading applet" error_downloading_1 = "There was an error downloading the applet: %s" not_installed = "Not installed" uninstall = "Uninstall" delete_app_confirm = "Delete applet?" delete_app_desc = ("WARNING! Deleting an applet removes ALL associated data, " "including credentials, and this data will NOT be " "recoverable.") deleting_1 = "Deleting applet: %s" install_cap = "Install applet from CAP file" select_cap = "Select a CAP file" devices = "Devices" apps = "Available apps" installed_apps = "Installed apps" unknown = "Unknown" unknown_applet = "Unknown applet" unsupported_device = "The %s doesn't support this device." % app_name about_1 = "About: %s" libraries = "Library versions" about_link_1 = "For help and discussion, see our forum." copyright = "Copyright © Yubico" def _translate(qt): values = globals() for key, value in values.items(): if isinstance(value, basestring) and not key.startswith('_'): values[key] = qt.tr(value) yubikey-neo-manager-1.4.0/neoman/yubicommon/0000775000175000017500000000000012621055514020675 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/neoman/yubicommon/__init__.py0000664000175000017500000000256212565114033023012 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. __version__ = '0.1.0' yubikey-neo-manager-1.4.0/neoman/yubicommon/qt/0000775000175000017500000000000012621055514021321 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/neoman/yubicommon/qt/__init__.py0000664000175000017500000000435112565114033023434 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import absolute_import from PySide import QtGui from .utils import * from .classes import * from .worker import * from .settings import * import sys import traceback # Font fixes for OSX if sys.platform == 'darwin': from platform import mac_ver mac_version = tuple(mac_ver()[0].split('.')) if (10, 9) <= mac_version < (10, 10): # Mavericks QtGui.QFont.insertSubstitution('.Lucida Grande UI', 'Lucida Grande') if (10, 10) <= mac_version: # Yosemite QtGui.QFont.insertSubstitution('.Helvetica Neue DeskInterface', 'Helvetica Neue') # Replace excepthook with one that releases the exception to prevent memory # leaks: def excepthook(typ, val, tback): traceback.print_exception(typ, val, tback) sys.exc_clear() del sys.last_value del sys.last_traceback del sys.last_type sys.excepthook = excepthook yubikey-neo-manager-1.4.0/neoman/yubicommon/qt/classes.py0000664000175000017500000001130012616633227023332 0ustar daindain00000000000000# Copyright (c) 2014 Yubico AB # All rights reserved. # # 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 . # # Additional permission under GNU GPL version 3 section 7 # # If you modify this program, or any covered work, by linking or # combining it with the OpenSSL project's OpenSSL library (or a # modified version of that library), containing parts covered by the # terms of the OpenSSL or SSLeay licenses, We grant you additional # permission to convey the resulting work. Corresponding Source for a # non-source form of such a combination shall include the source code # for the parts of OpenSSL used as well as that of the covered work. from __future__ import absolute_import from PySide import QtGui, QtCore from .worker import Worker import os import sys import time import importlib __all__ = ['Application', 'Dialog', 'MutexLocker'] TOP_SECTION = '%s' SECTION = '
%s' class Dialog(QtGui.QDialog): def __init__(self, *args, **kwargs): super(Dialog, self).__init__(*args, **kwargs) self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint) self._headers = _Headers() @property def headers(self): return self._headers def section(self, title): return self._headers.section(title) class _Headers(object): def __init__(self): self._first = True def section(self, title): if self._first: self._first = False section = TOP_SECTION % title else: section = SECTION % title return QtGui.QLabel(section) class _MainWindow(QtGui.QMainWindow): def __init__(self): super(_MainWindow, self).__init__() self._widget = None def customEvent(self, event): event.callback() event.accept() class Application(QtGui.QApplication): def __init__(self, m=None): super(Application, self).__init__(sys.argv) self.window = _MainWindow() if m: m._translate(self) self.worker = Worker(self.window, m) if getattr(sys, 'frozen', False): # we are running in a PyInstaller bundle self.basedir = sys._MEIPASS else: # we are running in a normal Python environment top_module_str = __package__.split('.')[0] top_module = importlib.import_module(top_module_str) self.basedir = os.path.dirname(top_module.__file__) def ensure_singleton(self, name=None): if not name: name = self.applicationName() from PySide import QtNetwork self._l_socket = QtNetwork.QLocalSocket() self._l_socket.connectToServer(name, QtCore.QIODevice.WriteOnly) if self._l_socket.waitForConnected(): self.worker.thread().quit() self.deleteLater() time.sleep(0.01) # Without this the process sometimes stalls. sys.exit(0) else: self._l_server = QtNetwork.QLocalServer() if not self._l_server.listen(name): QtNetwork.QLocalServer.removeServer(name) self._l_server.listen(name) self._l_server.newConnection.connect(self._show_window) def _show_window(self): self.window.show() self.window.activateWindow() def exec_(self): status = super(Application, self).exec_() self.worker.thread().quit() self.deleteLater() time.sleep(0.01) # Without this the process sometimes stalls. return status class MutexLocker(object): """Drop-in replacement for QMutexLocker that can start unlocked.""" def __init__(self, mutex, lock=True): self._mutex = mutex self._locked = False if lock: self.relock() def lock(self, try_lock=False): if try_lock: self._locked = self._mutex.tryLock() else: self._mutex.lock() self._locked = True return self._locked and self or None def relock(self): self.lock() def unlock(self): if self._locked: self._mutex.unlock() def __del__(self): self.unlock() yubikey-neo-manager-1.4.0/neoman/yubicommon/qt/settings.py0000664000175000017500000001044012565114033023531 0ustar daindain00000000000000# Copyright (c) 2014 Yubico AB # All rights reserved. # # 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 . # # Additional permission under GNU GPL version 3 section 7 # # If you modify this program, or any covered work, by linking or # combining it with the OpenSSL project's OpenSSL library (or a # modified version of that library), containing parts covered by the # terms of the OpenSSL or SSLeay licenses, We grant you additional # permission to convey the resulting work. Corresponding Source for a # non-source form of such a combination shall include the source code # for the parts of OpenSSL used as well as that of the covered work. from __future__ import absolute_import from PySide import QtCore from collections import MutableMapping __all__ = ['Settings', 'PySettings', 'convert_to'] def convert_to(value, target_type): if target_type is list: return [] if value is None else [value] if target_type is int: return 0 if value in ['', 'false', 'False'] else int(value) if target_type is float: return float(value) if target_type is bool: return value not in ['', 'false', 'False'] return value.encode('utf8') class SettingsGroup(object): def __init__(self, settings, mutex, group): self._settings = settings self._mutex = mutex self._group = group def __getattr__(self, method_name): if hasattr(self._settings, method_name): fn = getattr(self._settings, method_name) def wrapped(*args, **kwargs): try: self._mutex.lock() self._settings.beginGroup(self._group) return fn(*args, **kwargs) finally: self._settings.endGroup() self._mutex.unlock() return wrapped def rename(self, new_name): data = dict((key, self.value(key)) for key in self.childKeys()) self.remove('') self._group = new_name for k, v in data.items(): self.setValue(k, v) def __repr__(self): return 'Group(%s)' % self._group class Settings(QtCore.QObject): def __init__(self, q_settings, wrap=True): super(Settings, self).__init__() self._mutex = QtCore.QMutex(QtCore.QMutex.Recursive) self._wrap = wrap self._q_settings = q_settings def get_group(self, group): g = SettingsGroup(self._q_settings, self._mutex, group) if self._wrap: g = PySettings(g) return g @staticmethod def wrap(*args, **kwargs): return Settings(QtCore.QSettings(*args, **kwargs)) class PySettings(MutableMapping): def __init__(self, settings): self._settings = settings def __getattr__(self, method_name): return getattr(self._settings, method_name) def get(self, key, default=None): val = self._settings.value(key, default) if not isinstance(val, type(default)): val = convert_to(val, type(default)) return val def __getitem__(self, key): return self.get(key) def __setitem__(self, key, value): self._settings.setValue(key, value) def __delitem__(self, key): self._settings.remove(key) def __iter__(self): for key in list(self.keys()): yield key def __len__(self): return len(self._settings.childKeys()) def __contains__(self, key): return self._settings.contains(key) def keys(self): return self._settings.childKeys() def update(self, data): for key, value in list(data.items()): self[key] = value def clear(self): self._settings.remove('') def __repr__(self): return 'PySettings(%s)' % self._settings yubikey-neo-manager-1.4.0/neoman/yubicommon/qt/utils.py0000664000175000017500000000612112616633227023042 0ustar daindain00000000000000# Copyright (c) 2014 Yubico AB # All rights reserved. # # 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 . # # Additional permission under GNU GPL version 3 section 7 # # If you modify this program, or any covered work, by linking or # combining it with the OpenSSL project's OpenSSL library (or a # modified version of that library), containing parts covered by the # terms of the OpenSSL or SSLeay licenses, We grant you additional # permission to convey the resulting work. Corresponding Source for a # non-source form of such a combination shall include the source code # for the parts of OpenSSL used as well as that of the covered work. from __future__ import absolute_import from PySide import QtCore, QtGui from functools import wraps from inspect import getargspec __all__ = ['get_text', 'get_active_window'] class _DefaultMessages(object): def __init__(self, default_m, m=None): self._defaults = default_m self._m = m def __getattr__(self, method_name): if hasattr(self._m, method_name): return getattr(self._m, method_name) else: return getattr(self._defaults, method_name) def default_messages(_m, name='m'): def inner(fn): @wraps(fn) def wrapper(*args, **kwargs): index = getargspec(fn).args.index(name) if len(args) > index: args = list(args) args[index] = _DefaultMessages(_m, args[index]) else: kwargs[name] = _DefaultMessages(_m, kwargs.get(name)) return fn(*args, **kwargs) return wrapper return inner def get_text(*args, **kwargs): flags = ( QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowSystemMenuHint ) kwargs['flags'] = flags return QtGui.QInputDialog.getText(*args, **kwargs) def get_active_window(): active_win = QtGui.QApplication.activeWindow() if active_win is not None: return active_win wins = [w for w in QtGui.QApplication.topLevelWidgets() if isinstance(w, QtGui.QDialog) and w.isVisible()] if not wins: return QtCore.QCoreApplication.instance().window return wins[0] # TODO: If more than one candidates remain, find best one. def connect_once(signal, slot): def wrapped(*args, **kwargs): signal.disconnect(wrapped) slot(*args, **kwargs) signal.connect(wrapped) def is_minimized(window): """Returns True iff the window is minimized or has been sent to the tray""" return not window.isVisible() or window.isMinimized() yubikey-neo-manager-1.4.0/neoman/yubicommon/qt/worker.py0000664000175000017500000000723312565114033023210 0ustar daindain00000000000000# Copyright (c) 2014 Yubico AB # All rights reserved. # # 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 . # # Additional permission under GNU GPL version 3 section 7 # # If you modify this program, or any covered work, by linking or # combining it with the OpenSSL project's OpenSSL library (or a # modified version of that library), containing parts covered by the # terms of the OpenSSL or SSLeay licenses, We grant you additional # permission to convey the resulting work. Corresponding Source for a # non-source form of such a combination shall include the source code # for the parts of OpenSSL used as well as that of the covered work. from __future__ import absolute_import from PySide import QtGui, QtCore from functools import partial from .utils import get_active_window, default_messages import traceback class _Messages(object): wait = 'Please wait...' class _Event(QtCore.QEvent): EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) def __init__(self, callback): super(_Event, self).__init__(_Event.EVENT_TYPE) self._callback = callback def callback(self): self._callback() del self._callback class Worker(QtCore.QObject): _work_signal = QtCore.Signal(tuple) _work_done_0 = QtCore.Signal() @default_messages(_Messages) def __init__(self, window, m): super(Worker, self).__init__() self.window = window self.busy = QtGui.QProgressDialog('', None, 0, 0, window) self.busy.setWindowTitle(m.wait) self.busy.setWindowModality(QtCore.Qt.WindowModal) self.busy.setMinimumDuration(0) self.busy.setWindowFlags(self.busy.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint) self.busy.setAutoClose(True) self.work_thread = QtCore.QThread() self.moveToThread(self.work_thread) self.work_thread.start() self._work_signal.connect(self.work) self._work_done_0.connect(self.busy.reset) def post(self, title, fn, callback=None, return_errors=False): self.busy.setLabelText(title) self.busy.adjustPosition(get_active_window()) self.busy.show() self.post_bg(fn, callback, return_errors) def post_bg(self, fn, callback=None, return_errors=False): if isinstance(fn, tuple): fn = partial(fn[0], *fn[1:]) self._work_signal.emit((fn, callback, return_errors)) def post_fg(self, fn): if isinstance(fn, tuple): fn = partial(fn[0], *fn[1:]) event = _Event(fn) QtGui.QApplication.postEvent(self.window, event) @QtCore.Slot(tuple) def work(self, job): QtCore.QThread.msleep(10) # Needed to yield (fn, callback, return_errors) = job try: result = fn() except Exception as e: traceback.print_exc() result = e if not return_errors: def callback(e): raise e if callback: event = _Event(partial(callback, result)) QtGui.QApplication.postEvent(self.window, event) self._work_done_0.emit() yubikey-neo-manager-1.4.0/neoman/yubicommon/setup/0000775000175000017500000000000012621055514022035 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/neoman/yubicommon/setup/qt.py0000664000175000017500000000567012565114033023042 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import absolute_import from setuptools import Command from distutils.errors import DistutilsSetupError import os __dependencies__ = ['PySide'] __all__ = ['qt_resources'] class _qt_resources(Command): description = "convert file resources into code" user_options = [] boolean_options = [] _source = 'qt_resources' _target = '' def initialize_options(self): pass def finalize_options(self): self.cwd = os.getcwd() self.source = os.path.join(self.cwd, self._source) self.target = os.path.join(self.cwd, self._target) def _create_qrc(self): qrc = os.path.join(self.source, 'qt_resources.qrc') with open(qrc, 'w') as f: f.write('\n\n') for fname in os.listdir(self.source): f.write('%s\n' % fname) f.write('\n\n') return qrc def run(self): if os.getcwd() != self.cwd: raise DistutilsSetupError("Must be in package root!") qrc = self._create_qrc() self.execute(os.system, ('pyside-rcc "%s" -o "%s"' % (qrc, self.target),)) os.unlink(qrc) self.announce("QT resources compiled into %s" % self.target) def qt_resources(target, sourcedir='qt_resources'): target = target.replace('.', os.path.sep) if os.path.isdir(target): target = os.path.join(target, 'qt_resources.py') else: target += '.py' return type('qt_resources', (_qt_resources, object), { '_source': sourcedir, '_target': target }) yubikey-neo-manager-1.4.0/neoman/yubicommon/setup/__init__.py0000664000175000017500000002000412616633227024151 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import absolute_import __dependencies__ = [] __all__ = ['get_version', 'setup', 'release'] from setuptools import setup as _setup, find_packages, Command from setuptools.command.sdist import sdist from distutils import log from distutils.errors import DistutilsSetupError from datetime import date from glob import glob import os import re VERSION_PATTERN = re.compile(r"(?m)^__version__\s*=\s*['\"](.+)['\"]$") DEPENDENCY_PATTERN = re.compile( r"(?m)__dependencies__\s*=\s*\[((['\"].+['\"]\s*(,\s*)?)+)\]") base_module = __name__.rsplit('.', 1)[0] def get_version(module_name_or_file=None): """Return the current version as defined by the given module/file.""" if module_name_or_file is None: parts = base_module.split('.') module_name_or_file = parts[0] if len(parts) > 1 else \ find_packages(exclude=['test', 'test.*'])[0] if os.path.isdir(module_name_or_file): module_name_or_file = os.path.join(module_name_or_file, '__init__.py') with open(module_name_or_file, 'r') as f: match = VERSION_PATTERN.search(f.read()) return match.group(1) def get_dependencies(module): basedir = os.path.dirname(__file__) fn = os.path.join(basedir, module + '.py') if os.path.isfile(fn): with open(fn, 'r') as f: match = DEPENDENCY_PATTERN.search(f.read()) if match: return [s.strip().strip('"\'') for s in match.group(1).split(',')] return [] def get_package(module): return base_module + '.' + module def setup(**kwargs): # TODO: Find a better way to pass this to a command. os.environ['setup_long_name'] = kwargs.pop('long_name', kwargs.get('name')) if 'version' not in kwargs: kwargs['version'] = get_version() packages = kwargs.setdefault( 'packages', find_packages(exclude=['test', 'test.*', base_module + '.*'])) packages.append(__name__) install_requires = kwargs.setdefault('install_requires', []) for yc_module in kwargs.pop('yc_requires', []): packages.append(get_package(yc_module)) for dep in get_dependencies(yc_module): if dep not in install_requires: install_requires.append(dep) cmdclass = kwargs.setdefault('cmdclass', {}) cmdclass.setdefault('release', release) cmdclass.setdefault('build_man', build_man) cmdclass.setdefault('sdist', custom_sdist) return _setup(**kwargs) class custom_sdist(sdist): def run(self): self.run_command('build_man') # Run if available: if 'qt_resources' in self.distribution.cmdclass: self.run_command('qt_resources') sdist.run(self) class build_man(Command): description = "create man pages from asciidoc source" user_options = [] boolean_options = [] def initialize_options(self): pass def finalize_options(self): self.cwd = os.getcwd() self.fullname = self.distribution.get_fullname() self.name = self.distribution.get_name() self.version = self.distribution.get_version() def run(self): if os.getcwd() != self.cwd: raise DistutilsSetupError("Must be in package root!") for fname in glob(os.path.join('man', '*.adoc')): self.announce("Converting: " + fname, log.INFO) self.execute(os.system, ('a2x -d manpage -f manpage "%s"' % fname,)) class release(Command): description = "create and release a new version" user_options = [ ('keyid', None, "GPG key to sign with"), ('skip-tests', None, "skip running the tests"), ('pypi', None, "publish to pypi"), ] boolean_options = ['skip-tests', 'pypi'] def initialize_options(self): self.keyid = None self.skip_tests = 0 self.pypi = 0 def finalize_options(self): self.cwd = os.getcwd() self.fullname = self.distribution.get_fullname() self.name = self.distribution.get_name() self.version = self.distribution.get_version() def _verify_version(self): with open('NEWS', 'r') as news_file: line = news_file.readline() now = date.today().strftime('%Y-%m-%d') if not re.search(r'Version %s \(released %s\)' % (self.version, now), line): raise DistutilsSetupError("Incorrect date/version in NEWS!") def _verify_tag(self): if os.system('git tag | grep -q "^%s\$"' % self.fullname) == 0: raise DistutilsSetupError( "Tag '%s' already exists!" % self.fullname) def _verify_not_dirty(self): if os.system('git diff --shortstat | grep -q "."') == 0: raise DistutilsSetupError("Git has uncommitted changes!") def _sign(self): if os.path.isfile('dist/%s.tar.gz.asc' % self.fullname): # Signature exists from upload, re-use it: sign_opts = ['--output dist/%s.tar.gz.sig' % self.fullname, '--dearmor dist/%s.tar.gz.asc' % self.fullname] else: # No signature, create it: sign_opts = ['--detach-sign', 'dist/%s.tar.gz' % self.fullname] if self.keyid: sign_opts.insert(1, '--default-key ' + self.keyid) self.execute(os.system, ('gpg ' + (' '.join(sign_opts)),)) if os.system('gpg --verify dist/%s.tar.gz.sig' % self.fullname) != 0: raise DistutilsSetupError("Error verifying signature!") def _tag(self): tag_opts = ['-s', '-m ' + self.fullname, self.fullname] if self.keyid: tag_opts[0] = '-u ' + self.keyid self.execute(os.system, ('git tag ' + (' '.join(tag_opts)),)) def run(self): if os.getcwd() != self.cwd: raise DistutilsSetupError("Must be in package root!") self._verify_version() self._verify_tag() self._verify_not_dirty() self.run_command('check') self.execute(os.system, ('git2cl > ChangeLog',)) self.run_command('sdist') if not self.skip_tests: try: self.run_command('test') except SystemExit as e: if e.code != 0: raise DistutilsSetupError("There were test failures!") if self.pypi: cmd_obj = self.distribution.get_command_obj('upload') cmd_obj.sign = True if self.keyid: cmd_obj.identity = self.keyid self.run_command('upload') self._sign() self._tag() self.announce("Release complete! Don't forget to:", log.INFO) self.announce("") self.announce(" git push && git push --tags", log.INFO) self.announce("") yubikey-neo-manager-1.4.0/neoman/yubicommon/setup/exe.py0000664000175000017500000000531612616670406023204 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from __future__ import absolute_import from setuptools import Command from distutils.errors import DistutilsSetupError import os import json import tempfile class executable(Command): description = "create an executable" user_options = [ ('debug', None, "build with debug flag"), ('data-files', None, "data files to include") ] boolean_options = ['debug'] def initialize_options(self): self.debug = 0 self.data_files = '' def finalize_options(self): self.cwd = os.getcwd() self.data_files = self.data_files.split() def run(self): if os.getcwd() != self.cwd: raise DistutilsSetupError("Must be in package root!") from PyInstaller.main import run as pyinst_run os.environ['pyinstaller_data'] = json.dumps({ 'debug': self.debug, 'name': self.distribution.get_name(), 'long_name': os.environ['setup_long_name'], 'data_files': self.data_files }) spec = tempfile.NamedTemporaryFile(suffix='.spec', delete=False) source = os.path.join(os.path.dirname(__file__), 'pyinstaller_spec.py') with open(source) as f: spec.write(f.read()) spec_name = spec.name spec.close() pyinst_run([spec_name]) os.unlink(spec_name) self.announce("Executable created!") yubikey-neo-manager-1.4.0/neoman/yubicommon/setup/pyinstaller_spec.py0000664000175000017500000001277312616670677026022 0ustar daindain00000000000000# -*- mode: python -*- # -*- encoding: utf-8 -*- from __future__ import absolute_import from __future__ import print_function import os import sys import json import errno import pkg_resources from glob import glob VS_VERSION_INFO = """ VSVersionInfo( ffi=FixedFileInfo( # filevers and prodvers should be always a tuple with four # items: (1, 2, 3, 4) # Set not needed items to zero 0. filevers=%(ver_tup)r, prodvers=%(ver_tup)r, # Contains a bitmask that specifies the valid bits 'flags'r mask=0x0, # Contains a bitmask that specifies the Boolean attributes # of the file. flags=0x0, # The operating system for which this file was designed. # 0x4 - NT and there is no need to change it. OS=0x4, # The general type of file. # 0x1 - the file is an application. fileType=0x1, # The function of the file. # 0x0 - the function is not defined for this fileType subtype=0x0, # Creation date and time stamp. date=(0, 0) ), kids=[ StringFileInfo( [ StringTable( u'040904E4', [StringStruct(u'FileDescription', u'%(name)s'), StringStruct(u'FileVersion', u'%(ver_str)s'), StringStruct(u'InternalName', u'%(internal_name)s'), StringStruct(u'LegalCopyright', u'Copyright © 2015 Yubico'), StringStruct(u'OriginalFilename', u'%(exe_name)s'), StringStruct(u'ProductName', u'%(name)s'), StringStruct(u'ProductVersion', u'%(ver_str)s')]) ]), VarFileInfo([VarStruct(u'Translation', [1033, 1252])]) ] )""" data = json.loads(os.environ['pyinstaller_data']) try: data = dict((k, v.encode('ascii') if isinstance(v, unicode) else v) for k, v in data.items()) except NameError: pass # Python 3, encode not needed. dist = pkg_resources.get_distribution(data['name']) ver_str = dist.version DEBUG = bool(data['debug']) NAME = data['long_name'] WIN = sys.platform in ['win32', 'cygwin'] OSX = sys.platform in ['darwin'] file_ext = '.exe' if WIN else '' if WIN: icon_ext = 'ico' elif OSX: icon_ext = 'icns' else: icon_ext = 'png' ICON = os.path.join('resources', '%s.%s' % (data['name'], icon_ext)) if not os.path.isfile(ICON): ICON = None # Generate scripts from entry_points. merge = [] entry_map = dist.get_entry_map() console_scripts = entry_map.get('console_scripts', {}) gui_scripts = entry_map.get('gui_scripts', {}) for ep in list(gui_scripts.values()) + list(console_scripts.values()): script_path = os.path.join(WORKPATH, ep.name + '-script.py') with open(script_path, 'w') as fh: fh.write("import %s\n" % ep.module_name) fh.write("%s.%s()\n" % (ep.module_name, '.'.join(ep.attrs))) merge.append( (Analysis([script_path], [dist.location], None, None, None, None), ep.name, ep.name + file_ext) ) MERGE(*merge) # Read version information on Windows. VERSION = None if WIN: VERSION = 'build/file_version_info.txt' global int_or_zero # Needed due to how this script is invoked def int_or_zero(v): try: return int(v) except ValueError: return 0 ver_tup = tuple(int_or_zero(v) for v in ver_str.split('.')) # Windows needs 4-tuple. if len(ver_tup) < 4: ver_tup += (0,) * (4-len(ver_tup)) elif len(ver_tup) > 4: ver_tup = ver_tup[:4] # Write version info. with open(VERSION, 'w') as f: f.write(VS_VERSION_INFO % { 'name': NAME, 'internal_name': data['name'], 'ver_tup': ver_tup, 'ver_str': ver_str, 'exe_name': NAME + file_ext }) pyzs = [PYZ(m[0].pure) for m in merge] exes = [] for (a, a_name, a_name_ext), pyz in zip(merge, pyzs): exe = EXE(pyz, a.scripts, exclude_binaries=True, name=a_name_ext, debug=DEBUG, strip=None, upx=True, console=DEBUG or a_name in console_scripts, append_pkg=not OSX, version=VERSION, icon=ICON) exes.append(exe) # Sign the executable if WIN: os.system("signtool.exe sign /t http://timestamp.verisign.com/scripts/timstamp.dll \"%s\"" % (exe.name)) collect = [] for (a, _, a_name), exe in zip(merge, exes): collect += [exe, a.binaries, a.zipfiles, a.datas] # Data files collect.append([(os.path.basename(fn), fn, 'DATA') for fn in data['data_files']]) # DLLs, dylibs and executables should go here. collect.append([(fn[4:], fn, 'BINARY') for fn in glob('lib/*')]) coll = COLLECT(*collect, strip=None, upx=True, name=NAME) # Create .app for OSX if OSX: app = BUNDLE(coll, name="%s.app" % NAME, version=ver_str, icon=ICON) qt_conf = 'dist/%s.app/Contents/Resources/qt.conf' % NAME qt_conf_dir = os.path.dirname(qt_conf) try: os.makedirs(qt_conf_dir) except OSError as e: if not (e.errno == errno.EEXIST and os.path.isdir(qt_conf_dir)): raise with open(qt_conf, 'w') as f: f.write('[Path]\nPlugins = plugins') # Create Windows installer if WIN: installer_cfg = 'resources/win-installer.nsi' if os.path.isfile(installer_cfg): os.system('makensis.exe -D"VERSION=%s" %s' % (ver_str, installer_cfg)) installer = "dist/%s-%s-win.exe" % (data['name'], ver_str) os.system("signtool.exe sign /t http://timestamp.verisign.com/scripts/timstamp.dll \"%s\"" % (installer)) print("Installer created: %s" % installer) yubikey-neo-manager-1.4.0/neoman/yubicommon/ctypes/0000775000175000017500000000000012621055514022204 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/neoman/yubicommon/ctypes/__init__.py0000664000175000017500000000263412565114033024321 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from .libloader import load_library __all__ = ['load_library'] yubikey-neo-manager-1.4.0/neoman/yubicommon/ctypes/libloader.py0000664000175000017500000002542012565114033024515 0ustar daindain00000000000000# ---------------------------------------------------------------------------- # Copyright (c) 2008 David James # Copyright (c) 2006-2008 Alex Holkner # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in # the documentation and/or other materials provided with the # distribution. # * Neither the name of pyglet nor the names of its # contributors may be used to endorse or promote products # derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ---------------------------------------------------------------------------- from __future__ import absolute_import import os.path import re import sys import glob import platform import ctypes import ctypes.util def _environ_path(name): if name in os.environ: return os.environ[name].split(":") else: return [] class LibraryLoader(object): def __init__(self): self.other_dirs = [] def load_library(self, libname, version=None): """Given the name of a library, load it.""" paths = self.getpaths(libname) for path in paths: if os.path.exists(path): return self.load(path) raise ImportError("%s not found." % libname) def load(self, path): """Given a path to a library, load it.""" try: # Darwin requires dlopen to be called with mode RTLD_GLOBAL instead # of the default RTLD_LOCAL. Without this, you end up with # libraries not being loadable, resulting in "Symbol not found" # errors if sys.platform == 'darwin': return ctypes.CDLL(path, ctypes.RTLD_GLOBAL) else: return ctypes.cdll.LoadLibrary(path) except OSError as e: raise ImportError(e) def getpaths(self, libname): """Return a list of paths where the library might be found.""" if os.path.isabs(libname): yield libname else: # FIXME / TODO return '.' and os.path.dirname(__file__) for path in self.getplatformpaths(libname): yield path path = ctypes.util.find_library(libname) if path: yield path def getplatformpaths(self, libname): return [] # Darwin (Mac OS X) class DarwinLibraryLoader(LibraryLoader): name_formats = ["lib%s.dylib", "lib%s.so", "lib%s.bundle", "%s.dylib", "%s.so", "%s.bundle", "%s"] def getplatformpaths(self, libname): if os.path.pathsep in libname: names = [libname] else: names = [format % libname for format in self.name_formats] for dir in self.getdirs(libname): for name in names: yield os.path.join(dir, name) def getdirs(self, libname): '''Implements the dylib search as specified in Apple documentation: http://developer.apple.com/documentation/DeveloperTools/Conceptual/ DynamicLibraries/Articles/DynamicLibraryUsageGuidelines.html Before commencing the standard search, the method first checks the bundle's ``Frameworks`` directory if the application is running within a bundle (OS X .app). ''' dyld_fallback_library_path = _environ_path( "DYLD_FALLBACK_LIBRARY_PATH") if not dyld_fallback_library_path: dyld_fallback_library_path = [os.path.expanduser('~/lib'), '/usr/local/lib', '/usr/lib'] dirs = [] if '/' in libname: dirs.extend(_environ_path("DYLD_LIBRARY_PATH")) else: dirs.extend(_environ_path("LD_LIBRARY_PATH")) dirs.extend(_environ_path("DYLD_LIBRARY_PATH")) dirs.extend(self.other_dirs) dirs.append(".") dirs.append(os.path.dirname(__file__)) if hasattr(sys, 'frozen') and sys.frozen == 'macosx_app': dirs.append(os.path.join( os.environ['RESOURCEPATH'], '..', 'Frameworks')) if hasattr(sys, 'frozen'): dirs.append(sys._MEIPASS) dirs.extend(dyld_fallback_library_path) return dirs # Posix class PosixLibraryLoader(LibraryLoader): _ld_so_cache = None def load_library(self, libname, version=None): try: return self.load(ctypes.util.find_library(libname)) except ImportError: return super(PosixLibraryLoader, self).load_library( libname, version) def _create_ld_so_cache(self): # Recreate search path followed by ld.so. This is going to be # slow to build, and incorrect (ld.so uses ld.so.cache, which may # not be up-to-date). Used only as fallback for distros without # /sbin/ldconfig. # # We assume the DT_RPATH and DT_RUNPATH binary sections are omitted. directories = [] for name in ("LD_LIBRARY_PATH", "SHLIB_PATH", # HPUX "LIBPATH", # OS/2, AIX "LIBRARY_PATH", # BE/OS ): if name in os.environ: directories.extend(os.environ[name].split(os.pathsep)) directories.extend(self.other_dirs) directories.append(".") directories.append(os.path.dirname(__file__)) try: directories.extend([dir.strip() for dir in open('/etc/ld.so.conf')]) except IOError: pass unix_lib_dirs_list = ['/lib', '/usr/lib', '/lib64', '/usr/lib64'] if sys.platform.startswith('linux'): # Try and support multiarch work in Ubuntu # https://wiki.ubuntu.com/MultiarchSpec bitage = platform.architecture()[0] if bitage.startswith('32'): # Assume Intel/AMD x86 compat unix_lib_dirs_list += [ '/lib/i386-linux-gnu', '/usr/lib/i386-linux-gnu'] elif bitage.startswith('64'): # Assume Intel/AMD x86 compat unix_lib_dirs_list += [ '/lib/x86_64-linux-gnu', '/usr/lib/x86_64-linux-gnu'] else: # guess... unix_lib_dirs_list += glob.glob('/lib/*linux-gnu') directories.extend(unix_lib_dirs_list) cache = {} lib_re = re.compile(r'lib(.*)\.s[ol]') ext_re = re.compile(r'\.s[ol]$') for dir in directories: try: for path in glob.glob("%s/*.s[ol]*" % dir): file = os.path.basename(path) # Index by filename if file not in cache: cache[file] = path # Index by library name match = lib_re.match(file) if match: library = match.group(1) if library not in cache: cache[library] = path except OSError: pass self._ld_so_cache = cache def getplatformpaths(self, libname): if self._ld_so_cache is None: self._create_ld_so_cache() result = self._ld_so_cache.get(libname) if result: yield result path = ctypes.util.find_library(libname) if path: yield os.path.join("/lib", path) # Windows class _WindowsLibrary(object): def __init__(self, path): self.cdll = ctypes.cdll.LoadLibrary(path) self.windll = ctypes.windll.LoadLibrary(path) def __getattr__(self, name): try: return getattr(self.cdll, name) except AttributeError: try: return getattr(self.windll, name) except AttributeError: raise class WindowsLibraryLoader(LibraryLoader): name_formats = ["%s.dll", "lib%s.dll", "%slib.dll"] def load_library(self, libname, version=None): try: result = LibraryLoader.load_library(self, libname, version) except ImportError: result = None if os.path.sep not in libname: formats = self.name_formats[:] if version: formats.append("lib%%s-%s.dll" % version) for name in formats: try: result = getattr(ctypes.cdll, name % libname) if result: break except WindowsError: result = None if result is None: try: result = getattr(ctypes.cdll, libname) except WindowsError: result = None if result is None: raise ImportError("%s not found." % libname) return result def load(self, path): return _WindowsLibrary(path) def getplatformpaths(self, libname): if os.path.sep not in libname: for name in self.name_formats: dll_in_current_dir = os.path.abspath(name % libname) if os.path.exists(dll_in_current_dir): yield dll_in_current_dir path = ctypes.util.find_library(name % libname) if path: yield path # Platform switching # If your value of sys.platform does not appear in this dict, please contact # the Ctypesgen maintainers. loaderclass = { "darwin": DarwinLibraryLoader, "cygwin": WindowsLibraryLoader, "win32": WindowsLibraryLoader } loader = loaderclass.get(sys.platform, PosixLibraryLoader)() def add_library_search_dirs(other_dirs): loader.other_dirs = other_dirs load_library = loader.load_library del loaderclass yubikey-neo-manager-1.4.0/neoman/device_u2f.py0000664000175000017500000001303712620116006021076 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from neoman.u2fh import * from ctypes import POINTER, byref, c_uint, c_size_t, create_string_buffer from neoman.device import BaseDevice from neoman.exc import YkNeoMgrError, ModeSwitchError from neoman.model.modes import MODE from neoman.yk4_utils import (parse_tlv_list, YK4_CAPA_TAG, YK4_CAPA1_OTP, YK4_CAPA1_CCID, YK4_CAPA1_U2F) import os def check(status): if status != 0: raise YkNeoMgrError(status) if u2fh_global_init(1 if 'NEOMAN_DEBUG' in os.environ else 0) != 0: raise Exception("Unable to initialize ykneomgr") libversion = u2fh_check_version(None) devs = POINTER(u2fh_devs)() check(u2fh_devs_init(byref(devs))) U2F_VENDOR_FIRST = 0x40 TYPE_INIT = 0x80 U2FHID_PING = TYPE_INIT | 0x01 U2FHID_YUBIKEY_DEVICE_CONFIG = TYPE_INIT | U2F_VENDOR_FIRST U2FHID_YK4_CAPABILITIES = TYPE_INIT | U2F_VENDOR_FIRST + 2 class U2FDevice(BaseDevice): device_type = 'U2F' version = (0, 0, 0) allowed_modes = (True, True, True) def __init__(self, devs, index, mode=MODE.mode_for_flags(False, False, True)): self._devs = devs self._index = index self._mode = mode self._serial = None @property def mode(self): return self._mode @property def serial(self): return self._serial def _sendrecv(self, cmd, data): buf_size = c_size_t(1024) resp = create_string_buffer(buf_size.value) check(u2fh_sendrecv(self._devs, self._index, cmd, data, len(data), resp, byref(buf_size))) return resp.raw[0:buf_size.value] def set_mode(self, mode): data = ('%02x0f0000' % mode).decode('hex') try: self._sendrecv(U2FHID_YUBIKEY_DEVICE_CONFIG, data) self._mode = mode except YkNeoMgrError: raise ModeSwitchError() def list_apps(self): return [] def poll(self): return hasattr(self, '_index') def close(self): if hasattr(self, '_index'): del self._index del self._devs class SKYDevice(U2FDevice): supported = False default_name = 'Security Key by Yubico' class YK4Device(U2FDevice): default_name = 'YubiKey 4' def __init__(self, devs, index, mode): super(YK4Device, self).__init__(devs, index, mode) self._read_capabilities() if self._cap == 0x07: # YK Edge should not allow CCID. self.default_name = 'YubiKey Edge' self.allowed_modes = (True, False, True) def _read_capabilities(self): data = '\0' resp = self._sendrecv(U2FHID_YK4_CAPABILITIES, data) self._cap_data = parse_tlv_list(resp[1:ord(resp[0]) + 1]) self._cap = int(self._cap_data.get(YK4_CAPA_TAG, '0').encode('hex'), 16) self.allowed_modes = ( bool(self._cap & YK4_CAPA1_OTP), bool(self._cap & YK4_CAPA1_CCID), bool(self._cap & YK4_CAPA1_U2F) ) def open_all_devices(): max_index = c_uint() status = u2fh_devs_discover(devs, byref(max_index)) if status == 0: # We have devices! devices = [] resp = create_string_buffer(1024) for index in range(max_index.value + 1): buf_size = c_size_t(1024) if u2fh_get_device_description( devs, index, resp, byref(buf_size)) == 0: if resp.value.startswith('Yubikey NEO'): mode = MODE.mode_for_flags( 'OTP' in resp.value, 'CCID' in resp.value, 'U2F' in resp.value ) devices.append(U2FDevice(devs, index, mode)) elif resp.value.startswith('Yubikey 4'): mode = MODE.mode_for_flags( 'OTP' in resp.value, 'CCID' in resp.value, 'U2F' in resp.value ) devices.append(YK4Device(devs, index, mode)) elif resp.value.startswith('Security Key by Yubico'): devices.append(SKYDevice(devs, index)) return devices else: # No devices! # u2fh_devs_done(devs) pass return [] yubikey-neo-manager-1.4.0/neoman/device_ccid.py0000664000175000017500000001727012617115763021326 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from neoman.ykneomgr import * from ctypes import POINTER, byref, c_size_t, create_string_buffer from neoman.device import BaseDevice from neoman.exc import YkNeoMgrError, ModeSwitchError from neoman.yk4_utils import (parse_tlv_list, YK4_CAPA_TAG, YK4_CAPA1_OTP, YK4_CAPA1_CCID, YK4_CAPA1_U2F) import os if ykneomgr_global_init(1 if 'NEOMAN_DEBUG' in os.environ else 0) != 0: raise Exception("Unable to initialize ykneomgr") libversion = ykneomgr_check_version(None) U2F_SELECT_1 = '00a4040008a0000006472f0001'.decode('hex') U2F_SELECT_2 = '00a4040007a0000005271002'.decode('hex') YK4_SELECT_MGMT = '00a4040008a000000527471117'.decode('hex') YK4_GET_CAPA = '001d0000'.decode('hex') class CCIDDevice(BaseDevice): device_type = 'CCID' version = (0, 0, 0) def __init__(self, dev, version=None, dev_str=None): self._dev = dev self._dev_str = dev_str self._key = None self._locked = True self._serial = ykneomgr_get_serialno(dev) or None self._mode = ykneomgr_get_mode(dev) self._version = ( ykneomgr_get_version_major(dev), ykneomgr_get_version_minor(dev), ykneomgr_get_version_build(dev) ) self._supports_u2f = self._has_u2f_applet() self._apps = None self._broken = False def _has_u2f_applet(self): return '\x90\x00' in [self.send_apdu(U2F_SELECT_1)[-2:], self.send_apdu(U2F_SELECT_2)[-2:]] def check(self, status): if status != 0: self._broken = True raise YkNeoMgrError(status) @property def allowed_modes(self): return (True, True, self._supports_u2f) @property def key(self): return self._key @key.setter def key(self, new_key): self._key = new_key @property def locked(self): return self._locked @property def mode(self): return self._mode @property def serial(self): return self._serial def unlock(self): self._locked = True if not self._key: raise ValueError("No transport key provided!") self.check(ykneomgr_authenticate(self._dev, self._key)) self._locked = False def set_mode(self, mode): if ykneomgr_modeswitch(self._dev, mode) != 0: raise ModeSwitchError() self._mode = mode def send_apdu(self, apdu): self._locked = True buf_size = c_size_t(1024) resp = create_string_buffer(buf_size.value) self.check(ykneomgr_send_apdu(self._dev, apdu, len(apdu), resp, byref(buf_size))) return resp.raw[0:buf_size.value] # Deprecated, DO NOT USE! def _list_apps(self, refresh=False): if refresh or self._apps is None: if self.locked: self.unlock() size = c_size_t() self.check(ykneomgr_applet_list(self._dev, None, byref(size))) applist = create_string_buffer(size.value) self.check(ykneomgr_applet_list(self._dev, applist, byref(size))) self._apps = applist.raw.strip('\0').split('\0') return self._apps def delete_app(self, aid): if self.locked: self.unlock() aid_bytes = aid.decode('hex') self.check(ykneomgr_applet_delete(self._dev, aid_bytes, len(aid_bytes))) def install_app(self, path): if self.locked: self.unlock() self.check(ykneomgr_applet_install(self._dev, create_string_buffer(path))) def close(self): if hasattr(self, '_dev'): ykneomgr_done(self._dev) del self._dev class YK4Device(CCIDDevice): default_name = 'YubiKey 4' allowed_modes = (False, False, False) def __init__(self, dev, version, dev_str): super(YK4Device, self).__init__(dev, version, dev_str) self._read_capabilities() if self._cap == 0x07: # YK Edge should not allow CCID. self.default_name = 'YubiKey Edge' self.allowed_modes = (True, False, True) def _read_capabilities(self): self.send_apdu(YK4_SELECT_MGMT) resp = self.send_apdu(YK4_GET_CAPA) resp, status = resp[:-2], resp[-2:] if status != '\x90\x00': resp = '\x00' if self.version == (4, 2, 4): # 4.2.4 has a bug with capabilities. resp = '0301013f'.decode('hex') self._cap_data = parse_tlv_list(resp[1:ord(resp[0]) + 1]) self._cap = int(self._cap_data.get(YK4_CAPA_TAG, '0').encode('hex'), 16) self.allowed_modes = ( bool(self._cap & YK4_CAPA1_OTP), bool(self._cap & YK4_CAPA1_CCID), bool(self._cap & YK4_CAPA1_U2F) ) @property def version(self): return self._version def check(status): if status != 0: raise YkNeoMgrError(status) def create_device(dev, dev_str=None): version = ( ykneomgr_get_version_major(dev), ykneomgr_get_version_minor(dev), ykneomgr_get_version_build(dev) ) if version[0] == 4: return YK4Device(dev, version, dev_str) return CCIDDevice(dev, version, dev_str) def open_first_device(): dev = POINTER(ykneomgr_dev)() check(ykneomgr_init(byref(dev))) try: check(ykneomgr_discover(dev)) except Exception: ykneomgr_done(dev) raise return create_device(dev) def open_all_devices(existing=None): dev = POINTER(ykneomgr_dev)() check(ykneomgr_init(byref(dev))) size = c_size_t() check(ykneomgr_list_devices(dev, None, byref(size))) devlist = create_string_buffer(size.value) check(ykneomgr_list_devices(dev, devlist, byref(size))) names = devlist.raw.strip('\0').split('\0') devices = [] for d in existing or []: if getattr(d, '_dev_str', None) in names: if d._broken: d.close() else: devices.append(d) names.remove(d._dev_str) for name in names: if not dev: dev = POINTER(ykneomgr_dev)() check(ykneomgr_init(byref(dev))) if ykneomgr_connect(dev, create_string_buffer(name)) == 0: devices.append(create_device(dev, name)) dev = None if dev: ykneomgr_done(dev) return devices yubikey-neo-manager-1.4.0/neoman/yk4_utils.py0000664000175000017500000000317312617063403021022 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. YK4_CAPA_TAG = 0x01 YK4_SERIAL_TAG = 0x01 YK4_CAPA1_OTP = 0x01 YK4_CAPA1_U2F = 0x02 YK4_CAPA1_CCID = 0x04 def parse_tlv_list(data): parsed = {} while data: t, l, data = ord(data[0]), ord(data[1]), data[2:] parsed[t], data = data[:l], data[l:] return parsed yubikey-neo-manager-1.4.0/neoman/u2fh.py0000664000175000017500000000555112565113112017734 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from ctypes import (Structure, POINTER, c_int, c_uint, c_uint8, c_uint16, c_char_p, c_size_t) from neoman.yubicommon.ctypes.libloader import load_library _lib = load_library('u2f-host', '0') u2fh_rc = c_int u2fh_initflags = c_uint def define(name, args, res=None): fn = getattr(_lib, name) fn.argtypes = args fn.restype = res return fn u2fh_check_version = define('u2fh_check_version', [c_char_p], c_char_p) u2fh_devs = type('u2fh_devs', (Structure,), {}) u2fh_global_init = define('u2fh_global_init', [u2fh_initflags], u2fh_rc) u2fh_global_done = define('u2fh_global_done', []) u2fh_devs_init = define('u2fh_devs_init', [POINTER(POINTER(u2fh_devs))], u2fh_rc) u2fh_devs_discover = define('u2fh_devs_discover', [POINTER(u2fh_devs), POINTER(c_uint)], u2fh_rc) u2fh_devs_done = define('u2fh_devs_done', [POINTER(u2fh_devs)]) u2fh_is_alive = define('u2fh_is_alive', [POINTER(u2fh_devs), c_uint], c_int) u2fh_sendrecv = define('u2fh_sendrecv', [POINTER(u2fh_devs), c_uint, c_uint8, c_char_p, c_uint16, c_char_p, POINTER(c_size_t)], u2fh_rc) u2fh_get_device_description = define('u2fh_get_device_description', [POINTER(u2fh_devs), c_int, c_char_p, POINTER(c_size_t)], u2fh_rc) __all__ = [x for x in globals().keys() if x.lower().startswith('u2fh')] yubikey-neo-manager-1.4.0/neoman/exc.py0000664000175000017500000000331112617115763017653 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. __all__ = [ 'YkNeoMgrError' ] class YkNeoMgrError(Exception): def __init__(self, code): super(YkNeoMgrError, self).__init__("ykneomgr error: %d" % code) self.status = code class ModeSwitchError(Exception): def __init__(self): super(ModeSwitchError, self).__init__( "Unable to set mode, is configuration locked?") yubikey-neo-manager-1.4.0/neoman/networker.py0000664000175000017500000000474012565113112021107 0ustar daindain00000000000000# Copyright (c) 2015 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from PySide import QtCore, QtNetwork from time import sleep class NetWorker: def __init__(self, worker): self._done = None self._dl = None self._worker = worker self._manager = QtNetwork.QNetworkAccessManager() self._manager.finished.connect(self._dl_done) def download(self, url, callback=None): self._done = False def mark_done(result): self._done = True callback(result) def dl(): self.download_bg(url, mark_done) while not self._done: sleep(0.1) self._worker.post('Downloading...', dl) def download_bg(self, url, callback=None): url = QtCore.QUrl(url) request = QtNetwork.QNetworkRequest(url) response = self._manager.get(request) self._dl = (request, response, callback) def _dl_done(self): (req, resp, callback) = self._dl del self._dl if callback: result = resp.error() if result is QtNetwork.QNetworkReply.NoError: result = resp.readAll() resp.close() callback(result)yubikey-neo-manager-1.4.0/neoman/ykneomgr.py0000664000175000017500000001051512565113112020717 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from ctypes import (Structure, POINTER, c_int, c_uint, c_uint8, c_char_p, c_size_t) from neoman.yubicommon.ctypes.libloader import load_library _lib = load_library('ykneomgr', '0') ykneomgr_rc = c_int ykneomgr_initflags = c_uint def define(name, args, res=None): fn = getattr(_lib, name) fn.argtypes = args fn.restype = res return fn ykneomgr_check_version = define('ykneomgr_check_version', [c_char_p], c_char_p) ykneomgr_dev = type('ykneomgr_dev', (Structure,), {}) ykneomgr_global_init = define('ykneomgr_global_init', [ykneomgr_initflags], ykneomgr_rc) ykneomgr_global_done = define('ykneomgr_global_done', []) ykneomgr_init = define('ykneomgr_init', [ POINTER(POINTER(ykneomgr_dev))], ykneomgr_rc) ykneomgr_done = define('ykneomgr_done', [POINTER(ykneomgr_dev)]) ykneomgr_list_devices = define('ykneomgr_list_devices', [POINTER(ykneomgr_dev), c_char_p, POINTER(c_size_t)], ykneomgr_rc) ykneomgr_connect = define('ykneomgr_connect', [POINTER(ykneomgr_dev), c_char_p], ykneomgr_rc) ykneomgr_discover = define('ykneomgr_discover', [POINTER(ykneomgr_dev)], ykneomgr_rc) ykneomgr_get_version_major = define('ykneomgr_get_version_major', [POINTER(ykneomgr_dev)], c_uint8) ykneomgr_get_version_minor = define('ykneomgr_get_version_minor', [POINTER(ykneomgr_dev)], c_uint8) ykneomgr_get_version_build = define('ykneomgr_get_version_build', [POINTER(ykneomgr_dev)], c_uint8) ykneomgr_get_mode = define('ykneomgr_get_mode', [POINTER(ykneomgr_dev)], c_uint8) ykneomgr_get_serialno = define('ykneomgr_get_serialno', [POINTER(ykneomgr_dev)], c_uint) ykneomgr_modeswitch = define('ykneomgr_modeswitch', [POINTER(ykneomgr_dev), c_uint8], ykneomgr_rc) ykneomgr_authenticate = define('ykneomgr_authenticate', [POINTER(ykneomgr_dev), c_char_p], ykneomgr_rc) ykneomgr_applet_list = define('ykneomgr_applet_list', [POINTER(ykneomgr_dev), c_char_p, POINTER(c_size_t)], ykneomgr_rc) ykneomgr_applet_delete = define('ykneomgr_applet_delete', [POINTER(ykneomgr_dev), c_char_p, c_size_t], ykneomgr_rc) ykneomgr_applet_install = define('ykneomgr_applet_install', [POINTER(ykneomgr_dev), c_char_p], ykneomgr_rc) ykneomgr_send_apdu = define('ykneomgr_send_apdu', [POINTER(ykneomgr_dev), c_char_p, c_size_t, c_char_p, POINTER(c_size_t)], ykneomgr_rc) __all__ = [x for x in globals().keys() if x.lower().startswith('ykneomgr')] yubikey-neo-manager-1.4.0/COPYING0000664000175000017500000000245712471132571016304 0ustar daindain00000000000000Copyright (c) 2013-2014 Yubico AB All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. yubikey-neo-manager-1.4.0/yubikey_neo_manager.egg-info/0000775000175000017500000000000012621055514022745 5ustar daindain00000000000000yubikey-neo-manager-1.4.0/yubikey_neo_manager.egg-info/PKG-INFO0000664000175000017500000000130512621055514024041 0ustar daindain00000000000000Metadata-Version: 1.1 Name: yubikey-neo-manager Version: 1.4.0 Summary: Tool for managing your YubiKey NEO configuration. Home-page: https://github.com/Yubico/yubikey-neo-manager Author: Yubico Open Source Maintainers Author-email: ossmaint@yubico.com License: BSD 2 clause Description: This is the long description Platform: UNKNOWN Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: X11 Applications :: Qt Classifier: Intended Audience :: End Users/Desktop Classifier: Topic :: Security :: Cryptography Classifier: Topic :: Utilities yubikey-neo-manager-1.4.0/yubikey_neo_manager.egg-info/requires.txt0000664000175000017500000000002012621055514025335 0ustar daindain00000000000000PySide pycrypto yubikey-neo-manager-1.4.0/yubikey_neo_manager.egg-info/SOURCES.txt0000664000175000017500000000335712621055514024641 0ustar daindain00000000000000COPYING ChangeLog MANIFEST.in NEWS README setup.cfg setup.py doc/Usage.adoc man/neoman.1 man/neoman.1.adoc neoman/__init__.py neoman/__main__.py neoman/appletdb.json neoman/device.py neoman/device_ccid.py neoman/device_otp.py neoman/device_u2f.py neoman/exc.py neoman/js_api.js neoman/messages.py neoman/networker.py neoman/qt_resources.py neoman/storage.py neoman/u2fh.py neoman/yk4_utils.py neoman/ykneomgr.py neoman/ykpers.py neoman/model/__init__.py neoman/model/applet.py neoman/model/jsapi.py neoman/model/modes.py neoman/model/neo.py neoman/view/__init__.py neoman/view/applet.py neoman/view/main.py neoman/view/nav.py neoman/view/neo.py neoman/view/tabs.py neoman/view/welcome.py neoman/yubicommon/__init__.py neoman/yubicommon/ctypes/__init__.py neoman/yubicommon/ctypes/libloader.py neoman/yubicommon/qt/__init__.py neoman/yubicommon/qt/classes.py neoman/yubicommon/qt/settings.py neoman/yubicommon/qt/utils.py neoman/yubicommon/qt/worker.py neoman/yubicommon/setup/__init__.py neoman/yubicommon/setup/exe.py neoman/yubicommon/setup/pyinstaller_spec.py neoman/yubicommon/setup/qt.py qt_resources/icon_about.png qt_resources/icon_installed.png qt_resources/icon_not_installed.png qt_resources/icon_some_installed.png qt_resources/neoman.png resources/installer_bg.png resources/linux-fix-ccid-udev resources/neoman.desktop resources/neoman.xpm resources/osx-installer.pkgproj resources/win-installer.nsi resources/yubikey-neo-manager.icns resources/yubikey-neo-manager.ico resources/yubikey-neo-manager.png yubikey_neo_manager.egg-info/PKG-INFO yubikey_neo_manager.egg-info/SOURCES.txt yubikey_neo_manager.egg-info/dependency_links.txt yubikey_neo_manager.egg-info/entry_points.txt yubikey_neo_manager.egg-info/requires.txt yubikey_neo_manager.egg-info/top_level.txtyubikey-neo-manager-1.4.0/yubikey_neo_manager.egg-info/top_level.txt0000664000175000017500000000000712621055514025474 0ustar daindain00000000000000neoman yubikey-neo-manager-1.4.0/yubikey_neo_manager.egg-info/dependency_links.txt0000664000175000017500000000000112621055514027013 0ustar daindain00000000000000 yubikey-neo-manager-1.4.0/yubikey_neo_manager.egg-info/entry_points.txt0000664000175000017500000000005512621055514026243 0ustar daindain00000000000000[gui_scripts] neoman = neoman.__main__:main yubikey-neo-manager-1.4.0/setup.py0000775000175000017500000000513312617115763016766 0ustar daindain00000000000000# Copyright (c) 2013 Yubico AB # All rights reserved. # # Redistribution and use in source and binary forms, with or # without modification, are permitted provided that the following # conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. from neoman.yubicommon.setup.exe import executable from neoman.yubicommon.setup.qt import qt_resources from neoman.yubicommon.setup import setup setup( name='yubikey-neo-manager', long_name='YubiKey NEO Manager', author='Dain Nilsson', author_email='dain@yubico.com', maintainer='Yubico Open Source Maintainers', maintainer_email='ossmaint@yubico.com', url='https://github.com/Yubico/yubikey-neo-manager', description='Tool for managing your YubiKey NEO configuration.', long_description='This is the long description', license='BSD 2 clause', package_data={'neoman': ['appletdb.json', 'js_api.js']}, entry_points={ 'gui_scripts': ['neoman=neoman.__main__:main'] }, install_requires=['PySide', 'pycrypto'], yc_requires=['ctypes', 'qt'], cmdclass={'executable': executable, 'qt_resources': qt_resources('neoman')}, classifiers=[ 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Development Status :: 5 - Production/Stable', 'Environment :: X11 Applications :: Qt', 'Intended Audience :: End Users/Desktop', 'Topic :: Security :: Cryptography', 'Topic :: Utilities' ] ) yubikey-neo-manager-1.4.0/MANIFEST.in0000664000175000017500000000033412565113112016771 0ustar daindain00000000000000include release.py include qt_resources.py include COPYING include NEWS include ChangeLog include neoman/js_api.js include neoman/appletdb.json include resources/* include qt_resources/* include doc/*.adoc include man/* yubikey-neo-manager-1.4.0/README0000664000175000017500000000744012617063403016125 0ustar daindain00000000000000== YubiKey NEO Manager Tool for managing your YubiKey NEO configuration. Connecting multiple keys at once is supported, but only if CCID mode is active for all of them. Entypo pictograms by Daniel Bruce - www.entypo.com [IMPORTANT] ==== Yubico has learned of a security issue with the OpenPGP Card applet project that is used in the YubiKey NEO. This vulnerability applies to you only if you are using OpenPGP, and you have the OpenPGP applet version 1.0.9 or earlier. link:https://developers.yubico.com/ykneo-openpgp/SecurityAdvisory%202015-04-14.html[SecurityAdvisory 2015-04-14] ==== === Installation The recommended way to install this software including dependencies is by using the provided precompiled binaries for your platform. For Windows and OS X (10.7 and above), there are installers available for download https://developers.yubico.com/yubikey-neo-manager/Releases/[here]. For Ubuntu we have a https://launchpad.net/%7eyubico/+archive/ubuntu/stable[custom PPA] containing the https://launchpad.net/%7eyubico/+archive/ubuntu/stable/+packages?field.name_filter=yubikey-neo-manager&field.status_filter=published&field.series_filter=[yubikey-neo-manager] package. === Dependencies YubiKey NEO Manager requires PySide, libykneomgr, yubikey-personalization and libu2f-host. === Running tests Tests can be run using the "nosetests" command, from the python-nose package. Alternatively "python setup.py test" can be used, but this will cause PySide to be compiled from source, requiring the python-dev package. === Building binaries Binaries for Windows and OSX are built using PyInstaller. Get the source release file, yubikey-neo-manager-.tar.gz, and extract it. It should contain a single directory, henceforth refered to as the release directory. When building binaries for Windows or OS X, you will need to include .dll/.dylib files from the libykneomgr, yubikey-personalization, and libu2f-host projects. Create a subdirectory called "lib" in the release directory. Download the correct binary release for your architecture for each of the aforementioned projects from https://developers.yubico.com/ and extract the .dll/.dylib files for each of them together with the included dependencies to the "lib" directory you created previously. ==== Windows For Windows you will need python, PySide, PyCrypto, PyInstaller and Pywin32 installed (32 or 64-bit versions depending on the architecture of the binary your are building). To sign the executable you will need signtool.exe (from the Windows SDK) either copied into the root as well or in a location in your PATH, as well as a certificate in the Windows certificate store that you wish to sign with. Run "pyinstaller.exe resources/neoman.spec" from the main release directory. With NSIS installed, a Windows installer will be built as well. ==== OSX For OSX you need python, pyside, pycrypto, and pyinstaller installed. One way to install these dependencies is by using Homebrew: brew install python brew install pyside pip install PyInstaller pip install pycrypto NOTE: Homebrew will build backwards-incompatible binaries, so the resulting build will not run on an older version of OSX. For building distributable releases you can use MacPorts instead. Run "pyinstaller resources/neoman.spec" from the main release directory. This will create an .app in the dist directory. Sign the code using codesign: codesign -s 'Developer ID Application' dist/YubiKey\ NEO\ Manager.app --deep There is also a project file for use with http://s.sudre.free.fr/Packaging.html[Packages] located at `resources/neoman.pkgproj`. This can be used to create an installer for distribution, which you should sign prior to distribution: packagesbuild resources/neoman.pkgproj productsign --sign 'Developer ID Installer' dist/YubiKey\ NEO\ Manager.pkg dist/yubikey-neo-manager-mac.pkg yubikey-neo-manager-1.4.0/NEWS0000664000175000017500000000466312621050053015740 0ustar daindain00000000000000* Version 1.4.0 (released 2015-11-12) ** Added support for YK4 based devices. ** Fixed refresh of device name after change. * Version 1.3.0 (released 2015-05-18) ** Updated applet definitions to fix incorrect OpenPGP applet version. ** Fix displaying wrong firmware version in CCID mode. ** Base U2F support on if applet is available (CCID). ** Don't save window position as it causes problems with multi-monitor setups. * Version 1.2.1 (released 2015-04-10) ** Bugfix release: Fix mode switching when in U2F-only mode. * Version 1.2.0 (released 2015-04-10) ** Added support for YubiKey Edge. ** Get rid of help buttons in Windows dialogs. ** Better error handling when switching modes. * Version 1.1.0 (released 2014-12-01) ** Fixed font on OS X 10.10. ** Added support for recognizing YubiKey Plus. ** Fixed support for displaying standard YubiKeys. * Version 1.0.0 (released 2014-11-19) ** 1.x.x version (no changes from 0.2.6). * Version 0.2.6 (released 2014-11-18) ** Re-enable OTP in combination with U2F. * Version 0.2.5 (released 2014-11-03) ** Recover from getting into a bad state when CCID becomes temporarily unavailable (which was causing problems on OS X Yosemite). ** Fixed modes being incorrectly reported under some circumstances. * Version 0.2.4 (released 2014-10-27) ** Build and release related stuff, no new features. * Version 0.2.3 (released 2014-10-14) ** Use image assets from code instead of external files. * Version 0.2.2 (released 2014-09-26) ** Better handle multiple devices with no serial set. ** Don't display OTP/U2F note for devices without U2F support. * Version 0.2.1 (released 2014-09-26) ** Correctly display mode for OTP+U2F devices. ** Don't display firmware in modes where firmware cannot be read. ** Display unsupported Yubico devices. ** Disable OTP+U2F combinations as they aren't currently usable. * Version 0.2.0 (released 2014-09-16) ** Removed usage of card manager keys for normal use. ** Added support for U2F modes (if hardware supports it). ** Better support for composite devices. * Version 0.1.0 (released 2014-03-25) ** Added the ability to view installed applet versions. ** Updated ykneomgr with ability to send custom APDUs. * Version 0.0.2 (released 2014-03-20) ** Support for installing/removing applets. ** Support for multiple NEOs. ** Better support for platform specific packaging. * Version 0.0.1 (released 2013-11-13) ** Initial release supporting mode changing. yubikey-neo-manager-1.4.0/setup.cfg0000664000175000017500000000017512621055514017063 0ustar daindain00000000000000[executable] data_files = neoman/appletdb.json neoman/js_api.js [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0