Converted password change window to use NSGridView.

Errors are displayed if a KeePass database is selected as key file.
Password and key errors are now displayed separatly
This commit is contained in:
Michael Starke 2021-01-26 21:20:52 +01:00
parent e4fadce3d0
commit 5457d4dde0
3 changed files with 313 additions and 187 deletions

View File

@ -1,17 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17701" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17701"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPPasswordEditWindowController">
<connections>
<outlet property="changePasswordButton" destination="68" id="85"/>
<outlet property="errorTextField" destination="12" id="79"/>
<outlet property="hasPasswordSwitchButton" destination="yKc-I9-uzv" id="aUH-R4-WwP"/>
<outlet property="keyErrorTextField" destination="ibK-Px-Fvt" id="l7h-qa-idf"/>
<outlet property="keyfilePathControl" destination="4" id="63"/>
<outlet property="passwordErrorTextField" destination="12" id="79"/>
<outlet property="passwordRepeatTextField" destination="11" id="62"/>
<outlet property="passwordTextField" destination="9" id="61"/>
<outlet property="togglePasswordButton" destination="7" id="64"/>
@ -23,99 +24,14 @@
<window title="Change Password" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="1">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="403" height="219"/>
<rect key="contentRect" x="196" y="240" width="307" height="211"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
<view key="contentView" id="2">
<rect key="frame" x="0.0" y="0.0" width="403" height="210"/>
<rect key="frame" x="0.0" y="0.0" width="369" height="231"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<pathControl verticalHuggingPriority="750" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4" customClass="MPPathControl">
<rect key="frame" x="105" y="87" width="242" height="25"/>
<pathCell key="cell" selectable="YES" editable="YES" alignment="left" pathStyle="popUp" id="23" customClass="MPPathCell">
<font key="font" metaFont="system"/>
</pathCell>
</pathControl>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5">
<rect key="frame" x="53" y="91" width="49" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Keyfile:" id="22">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6">
<rect key="frame" x="108" y="60" width="236" height="23"/>
<buttonCell key="cell" type="roundTextured" title="Generate Keyfile" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="21">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="generateKey:" target="-2" id="66"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7">
<rect key="frame" x="352" y="145" width="31" height="23"/>
<constraints>
<constraint firstAttribute="width" constant="31" id="59"/>
</constraints>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSQuickLookTemplate" imagePosition="only" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="20">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8">
<rect key="frame" x="352" y="89" width="31" height="23"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSStopProgressTemplate" imagePosition="only" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="19">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="clearKey:" target="-2" id="65"/>
</connections>
</button>
<secureTextField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="9" customClass="HNHUISecureTextField">
<rect key="frame" x="108" y="148" width="236" height="20"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="Gin-yR-DMk"/>
</constraints>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter Password" drawsBackground="YES" usesSingleLineMode="YES" id="18">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
</secureTextField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="10">
<rect key="frame" x="51" y="121" width="51" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Repeat:" id="16">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<secureTextField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="11" customClass="HNHUISecureTextField">
<rect key="frame" x="108" y="118" width="236" height="20"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Repeat Password" drawsBackground="YES" usesSingleLineMode="YES" id="15">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
</secureTextField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="12">
<rect key="frame" x="161" y="176" width="131" height="14"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Mismatching Passwords" id="14">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="68">
<rect key="frame" x="240" y="13" width="149" height="32"/>
<rect key="frame" x="206" y="13" width="149" height="32"/>
<buttonCell key="cell" type="push" title="Change Password" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="69">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -125,7 +41,7 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="72">
<rect key="frame" x="158" y="13" width="82" height="32"/>
<rect key="frame" x="124" y="13" width="82" height="32"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="73">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
@ -137,59 +53,167 @@ Gw
<action selector="cancel:" target="-2" id="84"/>
</connections>
</button>
<button horizontalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="yKc-I9-uzv">
<rect key="frame" x="18" y="150" width="84" height="18"/>
<buttonCell key="cell" type="check" title="Password:" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="OQz-DA-SoY">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
<gridView xPlacement="leading" yPlacement="bottom" rowAlignment="none" translatesAutoresizingMaskIntoConstraints="NO" id="0Iv-td-ACj">
<rect key="frame" x="20" y="67" width="329" height="144"/>
<rows>
<gridRow id="Ljm-xA-9NW"/>
<gridRow id="Dv9-ND-6rX"/>
<gridRow id="mNb-JP-3YX"/>
<gridRow id="vQK-bD-mNH"/>
<gridRow id="DIe-Hz-bd0"/>
<gridRow id="TQt-iq-lMT"/>
</rows>
<columns>
<gridColumn xPlacement="trailing" id="uaf-ph-2zN"/>
<gridColumn xPlacement="fill" id="7oF-Xq-5de"/>
<gridColumn xPlacement="fill" id="clB-mU-Eba"/>
</columns>
<gridCells>
<gridCell row="Ljm-xA-9NW" column="uaf-ph-2zN" id="1U3-Im-v9n"/>
<gridCell row="Ljm-xA-9NW" column="7oF-Xq-5de" id="2bp-dG-V6t">
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="12">
<rect key="frame" x="90" y="130" width="204" height="14"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="PASSWORD_ERROR" id="14">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="Ljm-xA-9NW" column="clB-mU-Eba" id="blk-az-oHS"/>
<gridCell row="Dv9-ND-6rX" column="uaf-ph-2zN" id="JUU-XQ-60P">
<button key="contentView" horizontalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="yKc-I9-uzv">
<rect key="frame" x="4" y="102" width="84" height="18"/>
<buttonCell key="cell" type="check" title="Password:" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="OQz-DA-SoY">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</gridCell>
<gridCell row="Dv9-ND-6rX" column="7oF-Xq-5de" id="cw2-er-epO">
<secureTextField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="9" customClass="HNHUISecureTextField">
<rect key="frame" x="92" y="104" width="200" height="20"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="200" id="Gin-yR-DMk"/>
</constraints>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter Password" drawsBackground="YES" usesSingleLineMode="YES" id="18">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
</secureTextField>
</gridCell>
<gridCell row="Dv9-ND-6rX" column="clB-mU-Eba" id="ykQ-xV-MfJ"/>
<gridCell row="mNb-JP-3YX" column="uaf-ph-2zN" id="DTm-fw-duK">
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="10">
<rect key="frame" x="37" y="76" width="51" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Repeat:" id="16">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="mNb-JP-3YX" column="7oF-Xq-5de" id="OBv-b8-DJs">
<secureTextField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="11" customClass="HNHUISecureTextField">
<rect key="frame" x="92" y="76" width="200" height="20"/>
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Repeat Password" drawsBackground="YES" usesSingleLineMode="YES" id="15">
<font key="font" size="13" name="Menlo-Regular"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
<allowedInputSourceLocales>
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
</allowedInputSourceLocales>
</secureTextFieldCell>
</secureTextField>
</gridCell>
<gridCell row="mNb-JP-3YX" column="clB-mU-Eba" id="erv-Ur-nvi">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="7">
<rect key="frame" x="298" y="75" width="31" height="23"/>
<constraints>
<constraint firstAttribute="width" constant="31" id="59"/>
</constraints>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSQuickLookTemplate" imagePosition="only" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="20">
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
</button>
</gridCell>
<gridCell row="vQK-bD-mNH" column="uaf-ph-2zN" id="5U0-j9-rrv"/>
<gridCell row="vQK-bD-mNH" column="7oF-Xq-5de" id="8JE-Wh-Sad">
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ibK-Px-Fvt">
<rect key="frame" x="90" y="56" width="204" height="14"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="KEY_ERROR" id="EOD-dE-TFa">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" red="1" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="vQK-bD-mNH" column="clB-mU-Eba" id="fyu-1E-DpO"/>
<gridCell row="DIe-Hz-bd0" column="uaf-ph-2zN" id="Pjk-hs-Pb5">
<textField key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5">
<rect key="frame" x="39" y="28" width="49" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Keyfile:" id="22">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</gridCell>
<gridCell row="DIe-Hz-bd0" column="7oF-Xq-5de" id="o9J-f7-adq">
<pathControl key="contentView" verticalHuggingPriority="750" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4" customClass="MPPathControl">
<rect key="frame" x="89" y="24" width="206" height="25"/>
<pathCell key="cell" selectable="YES" editable="YES" alignment="left" pathStyle="popUp" id="23" customClass="MPPathCell">
<font key="font" metaFont="system"/>
</pathCell>
</pathControl>
</gridCell>
<gridCell row="DIe-Hz-bd0" column="clB-mU-Eba" id="miK-hQ-pkN">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="8">
<rect key="frame" x="298" y="27" width="31" height="23"/>
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="NSStopProgressTemplate" imagePosition="only" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="19">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="clearKey:" target="-2" id="65"/>
</connections>
</button>
</gridCell>
<gridCell row="TQt-iq-lMT" column="uaf-ph-2zN" id="nAI-ge-Vjb"/>
<gridCell row="TQt-iq-lMT" column="7oF-Xq-5de" id="dT5-pB-M7d">
<button key="contentView" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6">
<rect key="frame" x="92" y="-1" width="200" height="23"/>
<buttonCell key="cell" type="roundTextured" title="Generate Keyfile" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="21">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="generateKey:" target="-2" id="66"/>
</connections>
</button>
</gridCell>
<gridCell row="TQt-iq-lMT" column="clB-mU-Eba" id="zle-AC-ZGd"/>
</gridCells>
</gridView>
</subviews>
<constraints>
<constraint firstItem="9" firstAttribute="top" secondItem="12" secondAttribute="bottom" constant="8" symbolic="YES" id="26"/>
<constraint firstItem="4" firstAttribute="leading" secondItem="5" secondAttribute="trailing" constant="8" symbolic="YES" id="27"/>
<constraint firstItem="10" firstAttribute="baseline" secondItem="11" secondAttribute="baseline" id="29"/>
<constraint firstItem="7" firstAttribute="leading" secondItem="9" secondAttribute="trailing" constant="8" symbolic="YES" id="30"/>
<constraint firstItem="4" firstAttribute="top" secondItem="11" secondAttribute="bottom" constant="8" symbolic="YES" id="35"/>
<constraint firstItem="7" firstAttribute="top" secondItem="9" secondAttribute="top" id="36"/>
<constraint firstItem="11" firstAttribute="leading" secondItem="10" secondAttribute="trailing" constant="8" symbolic="YES" id="37"/>
<constraint firstItem="6" firstAttribute="top" secondItem="4" secondAttribute="bottom" constant="8" symbolic="YES" id="39"/>
<constraint firstItem="12" firstAttribute="centerX" secondItem="9" secondAttribute="centerX" id="40"/>
<constraint firstItem="8" firstAttribute="centerY" secondItem="4" secondAttribute="centerY" id="41"/>
<constraint firstItem="4" firstAttribute="bottom" secondItem="5" secondAttribute="bottom" id="43"/>
<constraint firstItem="12" firstAttribute="top" secondItem="2" secondAttribute="top" constant="20" symbolic="YES" id="53"/>
<constraint firstAttribute="trailing" secondItem="8" secondAttribute="trailing" constant="20" symbolic="YES" id="56"/>
<constraint firstAttribute="trailing" secondItem="7" secondAttribute="trailing" constant="20" symbolic="YES" id="57"/>
<constraint firstAttribute="trailing" secondItem="68" secondAttribute="trailing" constant="20" symbolic="YES" id="71"/>
<constraint firstItem="68" firstAttribute="leading" secondItem="72" secondAttribute="trailing" constant="12" symbolic="YES" id="75"/>
<constraint firstItem="72" firstAttribute="top" secondItem="6" secondAttribute="bottom" constant="20" symbolic="YES" id="76"/>
<constraint firstAttribute="bottom" secondItem="72" secondAttribute="bottom" constant="20" symbolic="YES" id="77"/>
<constraint firstAttribute="bottom" secondItem="68" secondAttribute="bottom" constant="20" symbolic="YES" id="78"/>
<constraint firstItem="5" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="2" secondAttribute="leading" constant="20" symbolic="YES" id="4Yq-mp-X3O"/>
<constraint firstItem="4" firstAttribute="width" secondItem="11" secondAttribute="width" id="55p-Rc-8jw"/>
<constraint firstItem="0Iv-td-ACj" firstAttribute="leading" secondItem="2" secondAttribute="leading" constant="20" symbolic="YES" id="4Gf-qW-X3R"/>
<constraint firstItem="72" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="2" secondAttribute="leading" constant="20" symbolic="YES" id="5JM-Ve-z5Y"/>
<constraint firstItem="8" firstAttribute="leading" secondItem="4" secondAttribute="trailing" constant="8" id="7GY-2X-nJn"/>
<constraint firstItem="4" firstAttribute="leading" secondItem="5" secondAttribute="trailing" constant="8" id="7eR-m5-mhQ"/>
<constraint firstItem="9" firstAttribute="baseline" secondItem="yKc-I9-uzv" secondAttribute="baseline" id="DrZ-BA-xPv"/>
<constraint firstItem="7" firstAttribute="leading" secondItem="9" secondAttribute="trailing" constant="8" id="IqJ-u6-6jk"/>
<constraint firstItem="yKc-I9-uzv" firstAttribute="leading" secondItem="2" secondAttribute="leading" constant="20" symbolic="YES" id="OdM-OO-kNS"/>
<constraint firstItem="7" firstAttribute="leading" secondItem="9" secondAttribute="trailing" constant="8" symbolic="YES" id="PnG-bb-nYQ"/>
<constraint firstItem="11" firstAttribute="top" secondItem="9" secondAttribute="bottom" constant="10" symbolic="YES" id="Qe9-z3-Wa6"/>
<constraint firstItem="yKc-I9-uzv" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="2" secondAttribute="leading" constant="20" symbolic="YES" id="R8d-VG-2we"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="6" secondAttribute="trailing" constant="20" symbolic="YES" id="TUn-PZ-fb5"/>
<constraint firstItem="10" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="2" secondAttribute="leading" constant="20" symbolic="YES" id="UHJ-Fx-Kkf"/>
<constraint firstItem="6" firstAttribute="width" secondItem="11" secondAttribute="width" id="V37-mo-ah1"/>
<constraint firstItem="9" firstAttribute="leading" secondItem="yKc-I9-uzv" secondAttribute="trailing" constant="8" symbolic="YES" id="f8B-Dm-rGD"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="12" secondAttribute="trailing" constant="20" symbolic="YES" id="hmt-qe-o3D"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="11" secondAttribute="trailing" constant="20" symbolic="YES" id="nDO-Oh-tGz"/>
<constraint firstItem="6" firstAttribute="leading" secondItem="4" secondAttribute="leading" id="tie-Hu-X1C"/>
<constraint firstItem="12" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="2" secondAttribute="leading" constant="20" symbolic="YES" id="ukY-Gg-KY2"/>
<constraint firstItem="11" firstAttribute="width" secondItem="9" secondAttribute="width" id="wEk-Sj-XCb"/>
<constraint firstItem="6" firstAttribute="leading" secondItem="11" secondAttribute="leading" id="xV3-et-ECG"/>
<constraint firstItem="6" firstAttribute="leading" secondItem="9" secondAttribute="leading" id="zeJ-6i-fY3"/>
<constraint firstItem="0Iv-td-ACj" firstAttribute="top" secondItem="2" secondAttribute="top" constant="20" symbolic="YES" id="FVY-mT-b2G"/>
<constraint firstAttribute="trailing" secondItem="0Iv-td-ACj" secondAttribute="trailing" constant="20" symbolic="YES" id="q2z-sU-YCn"/>
<constraint firstItem="68" firstAttribute="top" relation="greaterThanOrEqual" secondItem="0Iv-td-ACj" secondAttribute="bottom" constant="20" symbolic="YES" id="s84-KY-RXX"/>
</constraints>
</view>
<point key="canvasLocation" x="-8" y="-14"/>
<point key="canvasLocation" x="73" y="-137"/>
</window>
</objects>
<resources>

View File

@ -39,13 +39,15 @@
@interface MPPasswordEditWindowController : HNHUISheetWindowController <NSTextFieldDelegate>
@property (weak) IBOutlet HNHUISecureTextField *passwordTextField;
@property (weak) IBOutlet HNHUISecureTextField *passwordRepeatTextField;
@property (weak) IBOutlet NSPathControl *keyfilePathControl;
@property (weak) IBOutlet NSButton *togglePasswordButton;
@property (weak) IBOutlet NSTextField *errorTextField;
@property (weak) IBOutlet NSButton *changePasswordButton;
@property (weak) IBOutlet NSButton *hasPasswordSwitchButton;
@property (strong) IBOutlet HNHUISecureTextField *passwordTextField;
@property (strong) IBOutlet HNHUISecureTextField *passwordRepeatTextField;
@property (strong) IBOutlet NSPathControl *keyfilePathControl;
@property (strong) IBOutlet NSButton *togglePasswordButton;
@property (strong) IBOutlet NSTextField *passwordErrorTextField;
@property (strong) IBOutlet NSTextField *keyErrorTextField;
@property (strong) IBOutlet NSButton *changePasswordButton;
@property (strong) IBOutlet NSButton *hasPasswordSwitchButton;
@property (strong) IBOutlet NSGridView *gridView;
- (IBAction)clearKey:(id)sender;
- (IBAction)generateKey:(id)sender;

View File

@ -22,17 +22,34 @@
#import "MPPasswordEditWindowController.h"
#import "MPDocument.h"
#import "MPPathControl.h"
#import "HNHUi/HNHUi.h"
#import "KeePassKit/KeePassKit.h"
typedef NS_ENUM(NSUInteger, MPPasswordEditPasswordError) {
MPPasswordEditPasswordErrorNone,
MPPasswordEditPasswordErrorNoPassword,
MPPasswordEditPasswordErrorRepeatMissmatch
};
typedef NS_ENUM(NSUInteger, MPPasswordEditKeyError) {
MPPasswordEditKeyErrorNone,
MPPasswordEditKeyErrorNoKey,
MPPasswordEditKeyErrorNotReachable,
MPPasswordEditKeyErrorIsCurrentDatabase,
MPPasswordEditKeyErrorIsKeePassDatabase,
};
@interface MPPasswordEditWindowController ()
@property (nonatomic, assign) BOOL showPassword;
@property (nonatomic, assign) BOOL enablePassword;
@property (nonatomic, assign) BOOL hasValidPasswordOrKey;
@property (nonatomic, weak) NSURL *keyURL;
@property (weak) NSGridRow *passwordErrorGridRow;
@property (weak) NSGridRow *keyErrorGridRow;
@end
@ -53,10 +70,14 @@
- (void)windowDidLoad {
[super windowDidLoad];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(_didChangeKeyURL:) name:MPPathControlDidSetURLNotification object:self.keyfilePathControl];
[self.togglePasswordButton bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(showPassword)) options:nil];
self.window.defaultButtonCell = self.changePasswordButton.cell;
MPDocument *document = self.document;
self.enablePassword = [document.compositeKey hasKeyOfClass:KPKPasswordKey.class];
self.passwordErrorGridRow = [self.gridView cellForView:self.passwordErrorTextField].row;
self.keyErrorGridRow = [self.gridView cellForView:self.keyErrorTextField].row;
}
- (void)updateView {
@ -77,9 +98,8 @@
[self.togglePasswordButton bind:NSEnabledBinding toObject:self withKeyPath:enablePasswordKeyPath options:nil];
[self.passwordRepeatTextField bind:NSEnabledBinding toObject:self withKeyPath:showPasswordKeyPath options:negateOption];
[self.passwordRepeatTextField bind:NSEnabledBinding toObject:self withKeyPath:enablePasswordKeyPath options:nil];
[self.errorTextField bind:NSHiddenBinding toObject:self withKeyPath:hasValidPasswordOrKeyKeyPath options:nil];
[self.changePasswordButton bind:NSEnabledBinding toObject:self withKeyPath:hasValidPasswordOrKeyKeyPath options:nil];
[self.keyfilePathControl bind:NSValueBinding toObject:self withKeyPath:NSStringFromSelector(@selector(keyURL)) options:nil];
self.passwordRepeatTextField.delegate = self;
self.passwordTextField.delegate = self;
@ -98,10 +118,7 @@
[self _verifyPasswordAndKey];
}
}
- (void)setKeyURL:(NSURL *)keyURL {
_keyURL = keyURL;
[self _verifyPasswordAndKey];
}
- (void)setEnablePassword:(BOOL)enablePassword {
if(_enablePassword != enablePassword) {
_enablePassword = enablePassword;
@ -110,6 +127,7 @@
NSString *repeatPlaceHolder = _enablePassword ? NSLocalizedString(@"PASSWORD_INPUT_REPEAT_PASSWORD", "Placeholder for the repeat password field to aks for the repeated password") : NSLocalizedString(@"PASSWORD_INPUT_NO_PASSWORD", "Placeholder for the repeat password input if passwords are disabled");
self.passwordTextField.placeholderString = passwordPlaceHolder;
self.passwordRepeatTextField.placeholderString = repeatPlaceHolder;
[self _verifyPasswordAndKey];
}
#pragma mark Actions
@ -126,7 +144,7 @@
}
- (IBAction)clearKey:(id)sender {
self.keyURL = nil;
self.keyfilePathControl.URL = nil;
}
- (IBAction)generateKey:(id)sender {
@ -143,7 +161,7 @@
NSError *error;
BOOL saveOk = [data writeToURL:keyURL options:NSDataWritingAtomic error:&error];
if(saveOk) {
self.keyURL = keyURL;
self.keyfilePathControl.URL = keyURL;
}
}
}];
@ -155,43 +173,125 @@
[self _verifyPasswordAndKey];
}
- (void)_verifyPasswordAndKey {
NSString *password = self.passwordTextField.stringValue;
NSString *repeat = self.passwordRepeatTextField.stringValue;
BOOL hasKey = (self.keyURL != nil);
BOOL keyOk = YES;
if(hasKey) {
keyOk = [self.keyURL checkResourceIsReachableAndReturnError:nil];
}
BOOL hasPassword = password.kpk_isNotEmpty;
if(!self.showPassword) {
hasPassword |= repeat.kpk_isNotEmpty;
}
BOOL passwordOk = YES;
if(hasPassword ) {
passwordOk = [password isEqualToString:repeat] || self.showPassword;
}
BOOL hasPasswordOrKey = (hasKey || hasPassword);
keyOk = hasKey ? keyOk : YES;
passwordOk = hasPassword ? passwordOk : YES;
self.hasValidPasswordOrKey = hasPasswordOrKey && passwordOk && keyOk;
if(!hasPasswordOrKey) {
self.errorTextField.textColor = NSColor.controlTextColor;
self.errorTextField.stringValue = NSLocalizedString(@"WARNING_NO_PASSWORD_OR_KEYFILE", "No Key or Password");
return; // all done
}
self.errorTextField.textColor = NSColor.redColor;
if(!passwordOk && !keyOk ) {
self.errorTextField.stringValue = NSLocalizedString(@"ERROR_PASSWORD_MISSMATCH_INVALID_KEYFILE", "Passwords do not match, keyfile is invalid");
}
else if(!passwordOk) {
self.errorTextField.stringValue = NSLocalizedString(@"ERROR_PASSWORD_MISSMATCH", "Passwords do not match");
}
else {
self.errorTextField.stringValue = NSLocalizedString(@"ERROR_INVALID_KEYFILE", "Keyfile not valid");
#pragma mark Notifications
- (void)_didChangeKeyURL:(NSNotification *)notification {
if(notification.object != self.keyfilePathControl) {
return;
}
[self _verifyPasswordAndKey];
}
#pragma mark UI update
- (void)_verifyPasswordAndKey {
self.passwordErrorGridRow.hidden = YES;
self.keyErrorGridRow.hidden = YES;
self.keyErrorTextField.stringValue = @"";
self.passwordErrorTextField.stringValue = @"";
MPPasswordEditKeyError keyError = [self _verifyKey];
MPPasswordEditPasswordError passwordError = [self _verifyPassword];
self.keyErrorTextField.textColor = NSColor.controlColor;
self.passwordErrorTextField.textColor = NSColor.controlColor;
if(keyError == MPPasswordEditKeyErrorNoKey && passwordError == MPPasswordEditPasswordErrorNoPassword) {
self.passwordErrorTextField.stringValue = NSLocalizedString(@"WARNING_NO_PASSWORD", "No Key or Password");
self.passwordErrorGridRow.hidden = NO;
self.keyErrorTextField.stringValue = NSLocalizedString(@"WARNING_NO_KEYFILE", "No key file is set");
self.keyErrorGridRow.hidden = NO;
return;
}
switch(keyError) {
case MPPasswordEditKeyErrorNotReachable:
self.keyErrorTextField.stringValue = NSLocalizedString(@"ERROR_KEYFILE_NOT_FOUND", "Keyfile was not found");
self.keyErrorGridRow.hidden = NO;
self.keyErrorTextField.textColor = NSColor.redColor;
break;
case MPPasswordEditKeyErrorIsCurrentDatabase:
self.keyErrorTextField.stringValue = NSLocalizedString(@"ERROR_KEYFILE_IS_CURRENT_DATABASE", "The new key file is the current database.");
self.keyErrorGridRow.hidden = NO;
self.keyErrorTextField.textColor = NSColor.redColor;
break;
case MPPasswordEditKeyErrorIsKeePassDatabase:
self.keyErrorTextField.stringValue = NSLocalizedString(@"ERROR_KEYFILE_IS_KEEPASS_FILE", "Keyfile is a KeePass database.");
self.keyErrorGridRow.hidden = NO;
self.keyErrorTextField.textColor = NSColor.redColor;
break;
case MPPasswordEditKeyErrorNoKey:
if(!self.enablePassword) {
self.keyErrorTextField.stringValue = NSLocalizedString(@"WARNING_NO_KEYFILE", "No key file is set");
self.keyErrorGridRow.hidden = NO;
}
case MPPasswordEditKeyErrorNone:
break;
}
switch(passwordError) {
case MPPasswordEditPasswordErrorRepeatMissmatch:
self.passwordErrorTextField.stringValue = NSLocalizedString(@"ERROR_PASSWORD_MISSMATCH", "Passwords do not match");
self.passwordErrorGridRow.hidden = NO;
break;
case MPPasswordEditPasswordErrorNone:
case MPPasswordEditPasswordErrorNoPassword:
break;
}
self.hasValidPasswordOrKey = (passwordError == MPPasswordEditPasswordErrorNone && keyError == MPPasswordEditKeyErrorNone);
}
- (MPPasswordEditKeyError)_verifyKey {
NSURL *keyURL = self.keyfilePathControl.URL;
if(!keyURL) {
return MPPasswordEditKeyErrorNoKey;
}
if(![keyURL checkResourceIsReachableAndReturnError:nil]) {
return MPPasswordEditKeyErrorNotReachable;
}
/* TODO: exten KPKFileKey to do database checks internally */
NSDocument *document = (NSDocument *)self.document;
NSData *keyFileData = [NSData dataWithContentsOfURL:keyURL];
KPKFileVersion keyFileVersion = [KPKFormat.sharedFormat fileVersionForData:keyFileData];
if(keyFileVersion.format != KPKDatabaseFormatUnknown) {
if([document.fileURL isEqual:keyURL]) {
return MPPasswordEditKeyErrorIsCurrentDatabase;
}
return MPPasswordEditKeyErrorIsKeePassDatabase;
}
/* FIXME: check xml key */
return MPPasswordEditKeyErrorNone;
}
- (MPPasswordEditPasswordError)_verifyPassword {
if(!self.enablePassword) {
return MPPasswordEditPasswordErrorNone;
}
NSString *password = self.passwordTextField.stringValue;
NSString *repeat = self.passwordRepeatTextField.stringValue;
if(self.showPassword) {
if(password.kpk_isNotEmpty) {
return MPPasswordEditPasswordErrorNone;
}
return MPPasswordEditPasswordErrorNoPassword;
}
if(!password.kpk_isNotEmpty && !repeat.kpk_isNotEmpty) {
return MPPasswordEditPasswordErrorNoPassword;
}
if(![password isEqualToString:repeat]) {
return MPPasswordEditPasswordErrorRepeatMissmatch;
}
return MPPasswordEditPasswordErrorNone;
}
@end