2
0

OnePassword -> MasterPassword

This commit is contained in:
Maarten Billemont
2012-02-03 08:45:09 +01:00
parent 63600ab765
commit 960432577e
605 changed files with 152 additions and 60 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1906" systemVersion="11A511" targetRuntime="iOS.CocoaTouch.iPad" nextObjectID="24" propertyAccessControl="none" initialViewController="2">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="902"/>
</dependencies>
<scenes>
<scene sceneID="4">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="3" sceneMemberID="firstResponder"/>
<viewController id="2" customClass="OPMainViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8">
<rect key="frame" x="0.0" y="20" width="768" height="1004"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<navigationBar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="blackOpaque" id="13">
<rect key="frame" x="0.0" y="0.0" width="768" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<items>
<navigationItem title="Title" id="14">
<barButtonItem key="rightBarButtonItem" title="Info" id="15">
<connections>
<action selector="togglePopover:" destination="2" id="23"/>
</connections>
</barButtonItem>
</navigationItem>
</items>
</navigationBar>
</subviews>
<color key="backgroundColor" white="0.25" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<connections>
<segue destination="5" kind="popover" identifier="showAlternate" popoverAnchorBarButtonItem="15" id="22">
<popoverArrowDirection key="popoverArrowDirection" up="YES" down="YES" left="YES" right="YES"/>
<popoverPassthroughViews/>
</segue>
</connections>
</viewController>
</objects>
<point key="canvasLocation" x="-286" y="15"/>
</scene>
<scene sceneID="7">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="6" sceneMemberID="firstResponder"/>
<viewController id="5" customClass="OPFlipsideViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="9">
<rect key="frame" x="0.0" y="0.0" width="320" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<navigationBar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" barStyle="blackOpaque" id="17">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<items>
<navigationItem title="Title" id="18">
<barButtonItem key="leftBarButtonItem" systemItem="done" id="19">
<connections>
<action selector="done:" destination="5" id="21"/>
</connections>
</barButtonItem>
</navigationItem>
</items>
</navigationBar>
</subviews>
<color key="backgroundColor" white="0.25" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
<splitViewMasterSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
</viewController>
</objects>
<point key="canvasLocation" x="836" y="101"/>
</scene>
</scenes>
<classes>
<class className="OPFlipsideViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/OPFlipsideViewController.h"/>
<relationships>
<relationship kind="action" name="done:"/>
<relationship kind="outlet" name="delegate"/>
</relationships>
</class>
<class className="OPMainViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/OPMainViewController.h"/>
<relationships/>
</class>
</classes>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar" statusBarStyle="blackTranslucent"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination"/>
</simulatedMetricsContainer>
</document>

View File

@@ -0,0 +1,780 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="1.0" toolsVersion="1938" systemVersion="11D50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n">
<dependencies>
<development defaultVersion="4200" identifier="xcode"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="933"/>
</dependencies>
<scenes>
<scene sceneID="WkW-SR-cr2">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="jZj-N1-rhF" userLabel="First Responder" sceneMemberID="firstResponder"/>
<tableViewController id="NKe-nv-566" customClass="OPTypeViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="none" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="btl-G4-V0S">
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.12549020350000001" green="0.1411764771" blue="0.14901961389999999" alpha="1" colorSpace="calibratedRGB"/>
<view key="tableFooterView" contentMode="scaleToFill" id="aNa-wb-cYK">
<rect key="frame" x="0.0" y="588" width="320" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<sections>
<tableViewSection id="gUv-FU-O36">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="204" id="NCB-rX-weq">
<rect key="frame" x="0.0" y="0.0" width="320" height="204"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="203"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Generated" lineBreakMode="tailTruncation" minimumFontSize="10" id="azh-GA-KA1">
<rect key="frame" x="20" y="20" width="280" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Bold" family="Gill Sans" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_list_first.png" id="WXs-ZQ-JuJ">
<rect key="frame" x="10" y="160" width="300" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<rect key="contentStretch" x="0.10000000000000001" y="0.20000000000000001" width="0.79999999999999982" height="0.59999999999999964"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Long Password" lineBreakMode="tailTruncation" minimumFontSize="10" id="QIm-RX-xY7">
<rect key="frame" x="20" y="160" width="280" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans" family="Gill Sans" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Word-like, 14 characters, contains symbols." lineBreakMode="tailTruncation" minimumFontSize="10" id="6iu-aM-lJA">
<rect key="frame" x="20" y="184" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" id="E4a-XS-Qlz">
<rect key="frame" x="23" y="49" width="280" height="112"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<string key="text">These types create a safe password for your site.
The passwords aren't saved anywhere. This is a major advantage: if you loose your device, your passwords cannot be stolen. You can use any other device to get all your passwords back, no need for restoring backups or any other pains.</string>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="re0-ZT-bnP">
<rect key="frame" x="0.0" y="204" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_list_middle.png" id="EWy-Eb-L5p">
<rect key="frame" x="10" y="0.0" width="300" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.10000000000000001" y="0.20000000000000001" width="0.79999999999999982" height="0.59999999999999964"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Medium Password" lineBreakMode="tailTruncation" minimumFontSize="10" id="5NA-XX-th4">
<rect key="frame" x="20" y="0.0" width="280" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans" family="Gill Sans" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Word-like, 8 characters, contains symbols." lineBreakMode="tailTruncation" minimumFontSize="10" id="MI2-JM-j4b">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="4pb-c9-i2D">
<rect key="frame" x="0.0" y="248" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_list_middle.png" id="Jqw-h1-g2X">
<rect key="frame" x="10" y="0.0" width="300" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.10000000000000001" y="0.20000000000000001" width="0.79999999999999982" height="0.59999999999999964"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Short Password" lineBreakMode="tailTruncation" minimumFontSize="10" id="iqW-mf-H1R">
<rect key="frame" x="20" y="0.0" width="280" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans" family="Gill Sans" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Word-like, 4 characters." lineBreakMode="tailTruncation" minimumFontSize="10" id="Zi3-26-3iq">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="ywW-4w-Wej">
<rect key="frame" x="0.0" y="292" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_list_middle.png" id="Son-EL-Drx">
<rect key="frame" x="10" y="0.0" width="300" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.10000000000000001" y="0.20000000000000001" width="0.79999999999999982" height="0.59999999999999964"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Basic Password" lineBreakMode="tailTruncation" minimumFontSize="10" id="Pim-A8-aib">
<rect key="frame" x="20" y="0.0" width="280" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans" family="Gill Sans" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="8 characters." lineBreakMode="tailTruncation" minimumFontSize="10" id="CYQ-D8-vNS">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="5p5-OD-zpn">
<rect key="frame" x="0.0" y="336" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_list_last.png" id="5nI-rL-CoO">
<rect key="frame" x="10" y="0.0" width="300" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.10000000000000001" y="0.20000000000000001" width="0.79999999999999982" height="0.59999999999999964"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="PIN" lineBreakMode="tailTruncation" minimumFontSize="10" id="Yu2-5k-AwW">
<rect key="frame" x="20" y="0.0" width="280" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans" family="Gill Sans" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="4 numbers." lineBreakMode="tailTruncation" minimumFontSize="10" id="5Zm-AH-bAe">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection id="Jqk-Jl-vVm">
<cells>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" rowHeight="164" id="OK2-fa-fDw">
<rect key="frame" x="0.0" y="380" width="320" height="164"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="163"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="User-specified" lineBreakMode="tailTruncation" minimumFontSize="10" id="146-3h-mdD">
<rect key="frame" x="20" y="20" width="280" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Bold" family="Gill Sans" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" lineBreakMode="tailTruncation" numberOfLines="0" minimumFontSize="10" id="Bbk-lL-BeB">
<rect key="frame" x="20" y="49" width="280" height="63"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<string key="text">If you need to specify a custom password for your site, use one of these types. The site's password will be encrypted using your master password.</string>
<fontDescription key="fontDescription" name="GillSans-LightItalic" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_list_first.png" id="fxL-ee-UVP">
<rect key="frame" x="10" y="120" width="300" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<rect key="contentStretch" x="0.10000000000000001" y="0.20000000000000001" width="0.79999999999999982" height="0.59999999999999964"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Personal" lineBreakMode="tailTruncation" minimumFontSize="10" id="kzc-rQ-74F">
<rect key="frame" x="20" y="120" width="280" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans" family="Gill Sans" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="AES-encrypted, backed up with iTunes/iCloud." lineBreakMode="tailTruncation" minimumFontSize="10" id="vNa-Yq-XIJ">
<rect key="frame" x="20" y="144" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="ePk-a9-aNi">
<rect key="frame" x="0.0" y="544" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="ui_list_last.png" id="PUy-Qk-CeF">
<rect key="frame" x="10" y="0.0" width="300" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.10000000000000001" y="0.20000000000000001" width="0.79999999999999982" height="0.59999999999999964"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Device Private" lineBreakMode="tailTruncation" minimumFontSize="10" id="2kB-0P-FeR">
<rect key="frame" x="20" y="0.0" width="280" height="24"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans" family="Gill Sans" pointSize="18"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" cocoaTouchSystemColor="darkTextColor"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="AES-encrypted, not backed up." lineBreakMode="tailTruncation" minimumFontSize="10" id="6S8-9Y-pzj">
<rect key="frame" x="20" y="24" width="280" height="20"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" name="GillSans-Light" family="Gill Sans" pointSize="14"/>
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="NKe-nv-566" id="5yH-j4-f9c"/>
<outlet property="delegate" destination="NKe-nv-566" id="O5k-hI-7Tf"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Type" id="rak-Td-wu1"/>
</tableViewController>
</objects>
<point key="canvasLocation" x="996" y="182"/>
</scene>
<scene sceneID="U26-Zf-euQ">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="mK2-p1-3zC" userLabel="First Responder" sceneMemberID="firstResponder"/>
<customObject id="0QO-2P-OhD" customClass="OPSearchDelegate">
<connections>
<outlet property="delegate" destination="PQa-Xl-A3x" id="O2f-mW-ab8"/>
<outlet property="searchDisplayController" destination="P8c-gf-nN3" id="exk-dS-Ui3"/>
<outlet property="searchTipContainer" destination="zOR-Du-qRL" id="lk6-2X-lIb"/>
</connections>
</customObject>
<searchDisplayController id="P8c-gf-nN3">
<connections>
<outlet property="delegate" destination="0QO-2P-OhD" id="gst-Hm-5ja"/>
<outlet property="searchBar" destination="qeo-n2-WVh" id="bFO-FC-Xdj"/>
<outlet property="searchContentsController" destination="PQa-Xl-A3x" id="iEu-t3-hJY"/>
<outlet property="searchResultsDataSource" destination="0QO-2P-OhD" id="XJh-rC-kId"/>
<outlet property="searchResultsDelegate" destination="0QO-2P-OhD" id="Bm8-Q3-lLA"/>
</connections>
</searchDisplayController>
<viewController id="PQa-Xl-A3x" customClass="OPMainViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ep0-Hn-5TR">
<rect key="frame" x="0.0" y="64" width="320" height="416"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="top" image="Content-Backdrop.png" id="0hY-LL-ITu">
<rect key="frame" x="0.0" y="44" width="320" height="372"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<view contentMode="scaleToFill" id="g9q-4d-ZgJ">
<rect key="frame" x="0.0" y="43" width="320" height="175"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="top" image="Content-Backdrop.png" id="enb-OH-DVZ">
<rect key="frame" x="0.0" y="0.0" width="320" height="175"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" alpha="0.80000000000000004" contentMode="scaleToFill" image="ui_panel_container.png" id="0Yh-Py-lB6">
<rect key="frame" x="11" y="20" width="298" height="87"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
</imageView>
<imageView userInteractionEnabled="NO" alpha="0.80000001192092896" contentMode="scaleToFill" image="ui_panel_display.png" id="cw7-HD-Wht">
<rect key="frame" x="11" y="20" width="298" height="86"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<rect key="contentStretch" x="0.050000000000000003" y="0.10000000000000001" width="0.89999999999999991" height="0.79999999999999982"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" id="Zji-Vg-VwX">
<rect key="frame" x="11" y="20" width="298" height="86"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="boldSystem" size="button"/>
<state key="normal">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="copyContent" destination="PQa-Xl-A3x" eventType="touchUpInside" id="9tS-J5-wlx"/>
</connections>
</button>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.50000000000000011" contentMode="left" text="apple.com" lineBreakMode="tailTruncation" minimumFontSize="10" id="gSK-aB-wNI">
<rect key="frame" x="25" y="20" width="270" height="26"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="S3cre7^Pa$swcrD" textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="fiX-10-fif">
<rect key="frame" x="20" y="46" width="280" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="textColor" red="0.47450980390000003" green="0.86666666670000003" blue="0.98431372549999996" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" name="Optima-ExtraBlack" family="Optima" pointSize="26"/>
<textInputTraits key="textInputTraits" autocorrectionType="no"/>
<connections>
<outlet property="delegate" destination="PQa-Xl-A3x" id="qOM-gq-c6g"/>
</connections>
</textField>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" alpha="0.50000000000000011" contentMode="left" text="1" textAlignment="right" lineBreakMode="tailTruncation" minimumFontSize="10" id="Iuf-np-e9C">
<rect key="frame" x="240" y="27" width="40" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="Optima-ExtraBlack" family="Optima" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
<color key="shadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<size key="shadowOffset" width="0.0" height="1"/>
</label>
<button opaque="NO" alpha="0.50000000000000011" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jec-mu-nPt">
<rect key="frame" x="274.5" y="18.5" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" image="icon_plus.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="incrementPasswordCounter" destination="PQa-Xl-A3x" eventType="touchUpInside" id="hMc-kb-yFA"/>
</connections>
</button>
<button opaque="NO" alpha="0.5" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9FS-fS-xH6">
<rect key="frame" x="275" y="18.5" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<inset key="contentEdgeInsets" minX="5" minY="5" maxX="5" maxY="5"/>
<state key="normal" image="icon_edit.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="editPassword" destination="PQa-Xl-A3x" eventType="touchUpInside" id="jZC-Jm-ZZ0"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" reversesTitleShadowWhenHighlighted="YES" lineBreakMode="middleTruncation" id="Cei-5z-uWE">
<rect key="frame" x="10" y="115" width="300" height="46"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<size key="titleShadowOffset" width="0.0" height="1"/>
<state key="normal" title="Long" backgroundImage="ui_button_standard_large.png">
<color key="titleColor" cocoaTouchSystemColor="lightTextColor"/>
<color key="titleShadowColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<segue destination="NKe-nv-566" kind="push" identifier="OP_Main_ChooseType" id="vw4-Vd-O6q"/>
</connections>
</button>
<view userInteractionEnabled="NO" alpha="0.0" contentMode="scaleToFill" id="v2m-Gf-pEV">
<rect key="frame" x="55" y="8" width="210" height="57"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="fdm-NG-GFC">
<rect key="frame" x="0.0" y="-1" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Tap to set a password." textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="ieN-QQ-PyR">
<rect key="frame" x="20" y="0.0" width="170" height="37"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="icon_edit.png" id="KEn-n3-qhX">
<rect key="frame" x="48.5" y="6.5" width="24" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<view clipsSubviews="YES" alpha="0.60000000000000009" contentMode="scaleToFill" id="61G-By-qLB">
<rect key="frame" x="0.0" y="216" width="320" height="200"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="Square-bottom.png" id="lbm-A0-3PK">
<rect key="frame" x="0.0" y="0.0" width="320" height="58"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
</imageView>
<webView opaque="NO" contentMode="scaleToFill" id="8FQ-x4-lR9">
<rect key="frame" x="0.0" y="1" width="320" height="199"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<connections>
<outlet property="delegate" destination="PQa-Xl-A3x" id="H1z-xP-1Pm"/>
</connections>
</webView>
</subviews>
<color key="backgroundColor" cocoaTouchSystemColor="scrollViewTexturedBackgroundColor"/>
</view>
<view alpha="0.0" contentMode="scaleToFill" id="yRY-qt-gz8">
<rect key="frame" x="10" y="230" width="300" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_alert_black.png" id="TUv-Tl-xTc">
<rect key="frame" x="0.0" y="0.0" width="300" height="180"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<rect key="contentStretch" x="0.25" y="0.6499999999999998" width="0.64999999999999969" height="0.10000000000000002"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Password Changed!" lineBreakMode="tailTruncation" minimumFontSize="10" id="ZdH-we-KcW">
<rect key="frame" x="70" y="20" width="210" height="21"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" id="jCg-t7-RuK">
<rect key="frame" x="20" y="60" width="260" height="100"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<string key="text">The password for apple.com has changed.
Don't forget to update the site with your new password! Your old password was:
L4m3P4sSw0rD</string>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="cX2-vD-vjc">
<rect key="frame" x="259" y="5" width="32" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_cancel.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="closeAlert" destination="PQa-Xl-A3x" eventType="touchUpInside" id="oJt-DU-l38"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<searchBar contentMode="redraw" barStyle="blackOpaque" placeholder="Site" id="qeo-n2-WVh">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<gestureRecognizers/>
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
<connections>
<outlet property="delegate" destination="PQa-Xl-A3x" id="oXp-0r-Gkl"/>
</connections>
</searchBar>
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="zOR-Du-qRL">
<rect key="frame" x="55" y="-27" width="210" height="57"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="tip_basic_black.png" id="ORD-Xv-bOQ">
<rect key="frame" x="0.0" y="-1" width="210" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Enter the site's name." textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" id="21b-bH-lR9">
<rect key="frame" x="20" y="0.0" width="170" height="37"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="icon_edit.png" id="4Xf-mC-295">
<rect key="frame" x="49" y="6" width="24" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
</subviews>
<color key="backgroundColor" red="0.14901960784313725" green="0.16470588235294117" blue="0.1803921568627451" alpha="1" colorSpace="calibratedRGB"/>
</view>
<navigationItem key="navigationItem" title="Master Password" id="hB9-S6-KHC">
<barButtonItem key="rightBarButtonItem" id="Csu-uI-sPX">
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="iwA-Sh-vZO">
<rect key="frame" x="283" y="6" width="32" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_question.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="toggleHelp" destination="PQa-Xl-A3x" eventType="touchUpInside" id="Ufm-QL-QUM"/>
</connections>
</button>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="alertBody" destination="jCg-t7-RuK" id="Aru-Nr-DY0"/>
<outlet property="alertContainer" destination="yRY-qt-gz8" id="gZx-90-Zgr"/>
<outlet property="alertTitle" destination="ZdH-we-KcW" id="VWi-aS-HRw"/>
<outlet property="contentContainer" destination="g9q-4d-ZgJ" id="Hgw-Hp-FHB"/>
<outlet property="contentField" destination="fiX-10-fif" id="b2c-gv-qMp"/>
<outlet property="contentTipBody" destination="ieN-QQ-PyR" id="flJ-gF-wbI"/>
<outlet property="contentTipContainer" destination="v2m-Gf-pEV" id="9zL-GR-kyH"/>
<outlet property="contentTipEditIcon" destination="KEn-n3-qhX" id="dDG-Nt-OLM"/>
<outlet property="helpContainer" destination="61G-By-qLB" id="Jwt-0d-ZAV"/>
<outlet property="helpView" destination="8FQ-x4-lR9" id="MOg-5s-kvK"/>
<outlet property="passwordCounter" destination="Iuf-np-e9C" id="CIm-Mk-nJh"/>
<outlet property="passwordEdit" destination="9FS-fS-xH6" id="YeB-HF-ZPk"/>
<outlet property="passwordIncrementer" destination="jec-mu-nPt" id="i9B-lX-zzX"/>
<outlet property="searchDisplayController" destination="P8c-gf-nN3" id="CLs-YI-7NC"/>
<outlet property="searchResultsController" destination="0QO-2P-OhD" id="xEC-gV-lHp"/>
<outlet property="searchTipContainer" destination="zOR-Du-qRL" id="X7h-Vh-iCE"/>
<outlet property="siteName" destination="gSK-aB-wNI" id="IIe-z8-zy8"/>
<outlet property="typeButton" destination="Cei-5z-uWE" id="4M1-d7-5Bh"/>
</connections>
</viewController>
</objects>
<point key="canvasLocation" x="455" y="182"/>
</scene>
<scene sceneID="Rt1-b4-sUB">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="7yf-G7-kVy" userLabel="First Responder" sceneMemberID="firstResponder"/>
<viewController id="qz3-eG-aEi" customClass="OPGuideViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="cwa-ct-2DY">
<rect key="frame" x="0.0" y="20" width="320" height="460"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsVerticalScrollIndicator="NO" id="Nr4-hi-8b2">
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="guide_page_0.png" id="eJP-cS-VRU">
<rect key="frame" x="0.0" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="guide_page_1.png" id="1J9-z9-h96">
<rect key="frame" x="320" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="guide_page_2.png" id="8kf-Wm-F3L">
<rect key="frame" x="640" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="guide_page_3.png" id="H5W-P4-o7O">
<rect key="frame" x="960" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="guide_page_4.png" id="IXz-T9-Umi">
<rect key="frame" x="1280" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="guide_page_5.png" id="Hd0-Or-naq">
<rect key="frame" x="1280" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="bottom" image="guide_page_6.png" id="1jq-Ic-GVZ">
<rect key="frame" x="1600" y="0.0" width="320" height="460"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" reversesTitleShadowWhenHighlighted="YES" lineBreakMode="middleTruncation" id="q93-J1-auj">
<rect key="frame" x="1610" y="394" width="300" height="46"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<size key="titleShadowOffset" width="0.0" height="1"/>
<state key="normal" title="Get started" backgroundImage="ui_button_green_large.png">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" red="0.194560533886145" green="0.30086678832116787" blue="0.1263640535337863" alpha="1" colorSpace="deviceRGB"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="close" destination="qz3-eG-aEi" eventType="touchUpInside" id="uYR-EJ-U6H"/>
</connections>
</button>
</subviews>
</scrollView>
</subviews>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
</view>
<connections>
<outlet property="scrollView" destination="Nr4-hi-8b2" id="8QD-sv-vu6"/>
</connections>
</viewController>
</objects>
<point key="canvasLocation" x="455" y="785"/>
</scene>
<scene sceneID="8r0-wA-Zre">
<objects>
<placeholder placeholderIdentifier="IBFirstResponder" id="Lcz-JH-B5B" userLabel="First Responder" sceneMemberID="firstResponder"/>
<navigationController id="KZF-fe-y9n" sceneMemberID="viewController">
<toolbarItems/>
<simulatedStatusBarMetrics key="simulatedStatusBarMetrics" statusBarStyle="blackTranslucent"/>
<navigationBar key="navigationBar" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" barStyle="blackOpaque" id="sif-x3-Fol">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="PQa-Xl-A3x" kind="relationship" relationship="rootViewController" id="LUg-eF-JQd"/>
<segue destination="qz3-eG-aEi" kind="modal" identifier="OP_Guide" id="vyG-wN-8hU"/>
</connections>
</navigationController>
</objects>
<point key="canvasLocation" x="-85" y="182"/>
</scene>
</scenes>
<resources>
<image name="Content-Backdrop.png" width="480" height="480"/>
<image name="Square-bottom.png" width="551" height="58"/>
<image name="guide_page_0.png" width="320" height="480"/>
<image name="guide_page_1.png" width="320" height="480"/>
<image name="guide_page_2.png" width="320" height="480"/>
<image name="guide_page_3.png" width="320" height="480"/>
<image name="guide_page_4.png" width="320" height="480"/>
<image name="guide_page_5.png" width="320" height="480"/>
<image name="guide_page_6.png" width="320" height="480"/>
<image name="icon_cancel.png" width="32" height="32"/>
<image name="icon_edit.png" width="32" height="32"/>
<image name="icon_plus.png" width="32" height="32"/>
<image name="icon_question.png" width="32" height="32"/>
<image name="tip_alert_black.png" width="235" height="81"/>
<image name="tip_basic_black.png" width="210" height="60"/>
<image name="ui_button_green_large.png" width="300" height="46"/>
<image name="ui_button_standard_large.png" width="300" height="46"/>
<image name="ui_list_first.png" width="300" height="35"/>
<image name="ui_list_last.png" width="300" height="35"/>
<image name="ui_list_middle.png" width="300" height="34"/>
<image name="ui_panel_container.png" width="300" height="87"/>
<image name="ui_panel_display.png" width="300" height="86"/>
</resources>
<classes>
<class className="OPGuideViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/OPGuideViewController.h"/>
<relationships>
<relationship kind="action" name="close"/>
<relationship kind="outlet" name="scrollView" candidateClass="UIScrollView"/>
</relationships>
</class>
<class className="OPMainViewController" superclassName="UIViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/OPMainViewController.h"/>
<relationships>
<relationship kind="action" name="closeAlert"/>
<relationship kind="action" name="copyContent"/>
<relationship kind="action" name="editPassword"/>
<relationship kind="action" name="incrementPasswordCounter"/>
<relationship kind="action" name="toggleHelp"/>
<relationship kind="outlet" name="alertBody" candidateClass="UITextView"/>
<relationship kind="outlet" name="alertContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="alertTitle" candidateClass="UILabel"/>
<relationship kind="outlet" name="contentContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="contentField" candidateClass="UITextField"/>
<relationship kind="outlet" name="contentTipBody" candidateClass="UILabel"/>
<relationship kind="outlet" name="contentTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="contentTipEditIcon" candidateClass="UIImageView"/>
<relationship kind="outlet" name="helpContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="helpView" candidateClass="UIWebView"/>
<relationship kind="outlet" name="passwordCounter" candidateClass="UILabel"/>
<relationship kind="outlet" name="passwordEdit" candidateClass="UIButton"/>
<relationship kind="outlet" name="passwordIncrementer" candidateClass="UIButton"/>
<relationship kind="outlet" name="searchResultsController" candidateClass="OPSearchDelegate"/>
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
<relationship kind="outlet" name="siteName" candidateClass="UILabel"/>
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
</relationships>
</class>
<class className="OPSearchDelegate" superclassName="NSObject">
<source key="sourceIdentifier" type="project" relativePath="./Classes/OPSearchDelegate.h"/>
<relationships>
<relationship kind="outlet" name="delegate"/>
<relationship kind="outlet" name="searchDisplayController" candidateClass="UISearchDisplayController"/>
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
</relationships>
</class>
<class className="OPTypeViewController" superclassName="UITableViewController">
<source key="sourceIdentifier" type="project" relativePath="./Classes/OPTypeViewController.h"/>
</class>
</classes>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar" statusBarStyle="blackTranslucent"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination"/>
</simulatedMetricsContainer>
</document>

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFiles</key>
<array>
<string>Icon.png</string>
<string>Icon@2x.png</string>
<string>Icon-72.png</string>
</array>
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>Icon.png</string>
<string>Icon@2x.png</string>
<string>Icon-72.png</string>
</array>
<key>UIPrerenderedIcon</key>
<true/>
</dict>
</dict>
<key>CFBundleIdentifier</key>
<string>com.lyndir.lhunath.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>[auto]</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>[auto]</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>© 2011-2012, Lyndir</string>
<key>UIMainStoryboardFile</key>
<string>MainStoryboard_iPhone</string>
<key>UIMainStoryboardFile~ipad</key>
<string>MainStoryboard_iPad</string>
<key>UIPrerenderedIcon</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleBlackOpaque</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,26 @@
//
// Prefix header for all source files of the 'MasterPassword' target in the 'MasterPassword' project
//
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#endif
#define PEARL
#define PEARL_CRYPTO
#define PEARL_UIKIT
#import "Pearl.h"
#import "Pearl-Crypto.h"
#import "Pearl-UIKit.h"
#import "OPTypes.h"
#import "OPConfig.h"

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>MasterPassword.xcdatamodel</string>
</dict>
</plist>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="872" systemVersion="11C74" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
<entity name="OPElementEntity" representedClassName="OPElementEntity" isAbstract="YES" syncable="YES">
<attribute name="lastUsed" attributeType="Date" syncable="YES"/>
<attribute name="mpHashHex" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="name" attributeType="String" indexed="YES" syncable="YES"/>
<attribute name="type" attributeType="Integer 16" defaultValueString="257" syncable="YES"/>
<attribute name="uses" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
</entity>
<entity name="OPElementGeneratedEntity" representedClassName="OPElementGeneratedEntity" parentEntity="OPElementEntity" syncable="YES">
<attribute name="counter" optional="YES" attributeType="Integer 16" defaultValueString="1" syncable="YES"/>
</entity>
<entity name="OPElementStoredEntity" representedClassName="OPElementStoredEntity" parentEntity="OPElementEntity" syncable="YES">
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
</entity>
<fetchRequest name="OPSearchElement" entity="OPElementEntity" predicateString="name BEGINSWITH[cd] $query AND mpHashHex == $mpHashHex"/>
<elements>
<element name="OPElementEntity" positionX="160" positionY="192" width="128" height="135"/>
<element name="OPElementGeneratedEntity" positionX="160" positionY="192" width="128" height="60"/>
<element name="OPElementStoredEntity" positionX="160" positionY="192" width="128" height="60"/>
</elements>
</model>

View File

@@ -0,0 +1,30 @@
//
// OPAppDelegate.h
// MasterPassword
//
// Created by Maarten Billemont on 24/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface OPAppDelegate : AbstractAppDelegate
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (strong, nonatomic) NSString *keyPhrase;
@property (strong, nonatomic) NSData *keyPhraseHash;
@property (strong, nonatomic) NSString *keyPhraseHashHex;
+ (OPAppDelegate *)get;
+ (NSManagedObjectModel *)managedObjectModel;
+ (NSManagedObjectContext *)managedObjectContext;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
- (void)showGuide;
- (void)loadKeyPhrase;
@end

View File

@@ -0,0 +1,412 @@
//
// OPAppDelegate.m
// MasterPassword
//
// Created by Maarten Billemont on 24/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import "OPAppDelegate.h"
#import "OPMainViewController.h"
@interface OPAppDelegate ()
+ (NSDictionary *)keyPhraseQuery;
+ (NSDictionary *)keyPhraseHashQuery;
- (void)forgetKeyPhrase;
- (void)loadStoredKeyPhrase;
- (void)askKeyPhrase;
@end
@implementation OPAppDelegate
@synthesize managedObjectModel = __managedObjectModel;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
@synthesize keyPhrase = _keyPhrase;
@synthesize keyPhraseHash = _keyPhraseHash;
@synthesize keyPhraseHashHex = _keyPhraseHashHex;
+ (void)initialize {
#ifdef DEBUG
[Logger get].autoprintLevel = LogLevelTrace;
[NSClassFromString(@"WebView") performSelector:@selector(_enableRemoteInspector)];
#endif
}
+ (NSDictionary *)keyPhraseQuery {
static NSDictionary *OPKeyPhraseQuery = nil;
if (!OPKeyPhraseQuery)
OPKeyPhraseQuery = [KeyChain createQueryForClass:kSecClassGenericPassword
attributes:[NSDictionary dictionaryWithObject:@"MasterPassword"
forKey:(__bridge id)kSecAttrService]
matches:nil];
return OPKeyPhraseQuery;
}
+ (NSDictionary *)keyPhraseHashQuery {
static NSDictionary *OPKeyPhraseHashQuery = nil;
if (!OPKeyPhraseHashQuery)
OPKeyPhraseHashQuery = [KeyChain createQueryForClass:kSecClassGenericPassword
attributes:[NSDictionary dictionaryWithObject:@"MasterPasswordHash"
forKey:(__bridge id)kSecAttrService]
matches:nil];
return OPKeyPhraseHashQuery;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIImage *navBarImage = [[UIImage imageNamed:@"ui_navbar_container"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
[[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsLandscapePhone];
[[UINavigationBar appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1.0], UITextAttributeTextColor,
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8], UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, -1)], UITextAttributeTextShadowOffset,
[UIFont fontWithName:@"Helvetica-Neue" size:0.0], UITextAttributeFont,
nil]];
UIImage *navBarButton = [[UIImage imageNamed:@"ui_navbar_button"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)];
UIImage *navBarBack = [[UIImage imageNamed:@"ui_navbar_back"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)];
[[UIBarButtonItem appearance] setBackgroundImage:navBarButton forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:navBarBack forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:nil forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
[[UIBarButtonItem appearance] setTitleTextAttributes:
[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0], UITextAttributeTextColor,
[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5], UITextAttributeTextShadowColor,
[NSValue valueWithUIOffset:UIOffsetMake(0, 1)], UITextAttributeTextShadowOffset,
[UIFont fontWithName:@"Helvetica-Neue" size:0.0], UITextAttributeFont,
nil]
forState:UIControlStateNormal];
UIImage *toolBarImage = [[UIImage imageNamed:@"ui_toolbar_container"] resizableImageWithCapInsets:UIEdgeInsetsMake(25, 5, 5, 5)];
[[UISearchBar appearance] setBackgroundImage:toolBarImage];
[[UIToolbar appearance] setBackgroundImage:toolBarImage forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
/*
UIImage *minImage = [[UIImage imageNamed:@"slider-minimum.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
UIImage *maxImage = [[UIImage imageNamed:@"slider-maximum.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)];
UIImage *thumbImage = [UIImage imageNamed:@"slider-handle.png"];
[[UISlider appearance] setMaximumTrackImage:maxImage forState:UIControlStateNormal];
[[UISlider appearance] setMinimumTrackImage:minImage forState:UIControlStateNormal];
[[UISlider appearance] setThumbImage:thumbImage forState:UIControlStateNormal];
UIImage *segmentSelected = [[UIImage imageNamed:@"segcontrol_sel.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
UIImage *segmentUnselected = [[UIImage imageNamed:@"segcontrol_uns.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
UIImage *segmentSelectedUnselected = [UIImage imageNamed:@"segcontrol_sel-uns.png"];
UIImage *segUnselectedSelected = [UIImage imageNamed:@"segcontrol_uns-sel.png"];
UIImage *segmentUnselectedUnselected = [UIImage imageNamed:@"segcontrol_uns-uns.png"];
[[UISegmentedControl appearance] setBackgroundImage:segmentUnselected forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setBackgroundImage:segmentSelected forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentUnselectedUnselected forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentSelectedUnselected forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segUnselectedSelected forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];*/
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if ([[OPConfig get].showQuickstart boolValue])
[self showGuide];
else
[self loadKeyPhrase];
}
- (void)showGuide {
[self.navigationController performSegueWithIdentifier:@"OP_Guide" sender:self];
}
- (void)loadKeyPhrase {
if ([[OPConfig get].forgetKeyPhrase boolValue]) {
[self forgetKeyPhrase];
return;
}
[self loadStoredKeyPhrase];
if (!self.keyPhrase) {
// Key phrase is not known. Ask user to set/specify it.
dbg(@"Key phrase not known. Will ask user.");
[self askKeyPhrase];
return;
}
}
- (void)forgetKeyPhrase {
dbg(@"Forgetting key phrase.");
[AlertViewController showAlertWithTitle:@"Changing Master Password"
message:
@"You've requested to change your master password.\n\n"
@"If you continue, your current sites and passwords will become unavailable.\n\n"
@"You can always change back to the old master password later.\n"
@"Your old sites and passwords will then become available again."
viewStyle:UIAlertViewStyleDefault
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert firstOtherButtonIndex]) {
// Key phrase reset. Delete it.
dbg(@"Deleting master key phrase and hash from key chain.");
[KeyChain deleteItemForQuery:[OPAppDelegate keyPhraseQuery]];
[KeyChain deleteItemForQuery:[OPAppDelegate keyPhraseHashQuery]];
}
[self loadKeyPhrase];
}
cancelTitle:[PearlStrings get].commonButtonAbort
otherTitles:[PearlStrings get].commonButtonContinue, nil];
[OPConfig get].forgetKeyPhrase = [NSNumber numberWithBool:NO];
}
- (void)loadStoredKeyPhrase {
if ([[OPConfig get].storeKeyPhrase boolValue]) {
// Key phrase is stored in keychain. Load it.
dbg(@"Loading master key phrase from key chain.");
NSData *keyPhraseData = [KeyChain dataOfItemForQuery:[OPAppDelegate keyPhraseQuery]];
dbg(@" -> Master key phrase %@.", keyPhraseData? @"found": @"NOT found");
self.keyPhrase = keyPhraseData? [[NSString alloc] initWithBytes:keyPhraseData.bytes length:keyPhraseData.length
encoding:NSUTF8StringEncoding]: nil;
} else {
// Key phrase should not be stored in keychain. Delete it.
dbg(@"Deleting master key phrase from key chain.");
[KeyChain deleteItemForQuery:[OPAppDelegate keyPhraseQuery]];
}
}
- (void)askKeyPhrase {
dispatch_async(dispatch_get_main_queue(), ^{
NSData *keyPhraseHash = [KeyChain dataOfItemForQuery:[OPAppDelegate keyPhraseHashQuery]];
dbg(@"Key phrase hash %@.", keyPhraseHash? @"known": @"NOT known");
[AlertViewController showAlertWithTitle:@"Master Password"
message:keyPhraseHash? @"Unlock with your master password:": @"Choose your master password:"
viewStyle:UIAlertViewStyleSecureTextInput
tappedButtonBlock:
^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex])
exit(0);
NSString *answer = [alert textFieldAtIndex:0].text;
if (![answer length]) {
// User didn't enter a key phrase.
[AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
message:@"No master password entered."
viewStyle:UIAlertViewStyleDefault
tappedButtonBlock:
^(UIAlertView *alert, NSInteger buttonIndex) {
exit(0);
} cancelTitle:@"Quit" otherTitles:nil];
}
NSData *answerHash = [answer hashWith:PearlDigestSHA512];
if (keyPhraseHash)
// A key phrase hash is known -> a key phrase is set.
// Make sure the user's entered key phrase matches it.
if (![keyPhraseHash isEqual:answerHash]) {
dbg(@"Key phrase hash mismatch. Expected: %@, answer: %@.", keyPhraseHash, answerHash);
[AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
message:
@"Incorrect master password.\n\n"
@"If you are trying to use the app with a different master password, "
@"flip the 'Change my password' option in Settings."
viewStyle:UIAlertViewStyleDefault
tappedButtonBlock:
^(UIAlertView *alert, NSInteger buttonIndex) {
exit(0);
} cancelTitle:@"Quit" otherTitles:nil];
return;
}
self.keyPhrase = answer;
} cancelTitle:@"Quit" otherTitles:@"Unlock", nil];
});
}
- (void)applicationWillResignActive:(UIApplication *)application {
if (![[OPConfig get].rememberKeyPhrase boolValue])
self.keyPhrase = nil;
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
+ (OPAppDelegate *)get {
return (OPAppDelegate *)[super get];
}
+ (NSManagedObjectContext *)managedObjectContext {
return [(OPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectContext];
}
+ (NSManagedObjectModel *)managedObjectModel {
return [(OPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectModel];
}
- (void)saveContext
{
NSError *error = nil;
if ([self.managedObjectContext hasChanges] && ![self.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
*/
err(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
- (void)setKeyPhrase:(NSString *)keyPhrase {
_keyPhrase = keyPhrase;
if (keyPhrase) {
self.keyPhraseHash = [keyPhrase hashWith:PearlDigestSHA512];
self.keyPhraseHashHex = [self.keyPhraseHash encodeHex];
dbg(@"Updating master key phrase hash to: %@.", self.keyPhraseHashHex);
[KeyChain addOrUpdateItemForQuery:[OPAppDelegate keyPhraseHashQuery]
withAttributes:[NSDictionary dictionaryWithObject:self.keyPhraseHash
forKey:(__bridge id)kSecValueData]];
if ([[OPConfig get].storeKeyPhrase boolValue]) {
dbg(@"Storing master key phrase in key chain.");
[KeyChain addOrUpdateItemForQuery:[OPAppDelegate keyPhraseQuery]
withAttributes:[NSDictionary dictionaryWithObject:[keyPhrase dataUsingEncoding:NSUTF8StringEncoding]
forKey:(__bridge id)kSecValueData]];
}
}
}
#pragma mark - Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MasterPassword" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL
options:[NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, NSMigratePersistentStoresAutomaticallyOption,
(id)kCFBooleanTrue, NSInferMappingModelAutomaticallyOption,
nil]
error:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
err(@"Unresolved error %@, %@", error, [error userInfo]);
#if DEBUG
wrn(@"Deleted datastore: %@", storeURL);
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
#endif
@throw [NSException exceptionWithName:error.domain reason:error.localizedDescription
userInfo:[NSDictionary dictionaryWithObject:error forKey:@"cause"]];
}
return __persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end

20
MasterPassword/OPConfig.h Normal file
View File

@@ -0,0 +1,20 @@
//
// OPConfig.h
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
@interface OPConfig : Config
@property (nonatomic, retain) NSNumber *dataStoreError;
@property (nonatomic, retain) NSNumber *storeKeyPhrase;
@property (nonatomic, retain) NSNumber *rememberKeyPhrase;
@property (nonatomic, retain) NSNumber *forgetKeyPhrase;
@property (nonatomic, retain) NSNumber *helpHidden;
@property (nonatomic, retain) NSNumber *showQuickstart;
+ (OPConfig *)get;
@end

38
MasterPassword/OPConfig.m Normal file
View File

@@ -0,0 +1,38 @@
//
// OPConfig.m
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPConfig.h"
@implementation OPConfig
@dynamic dataStoreError, storeKeyPhrase, rememberKeyPhrase, forgetKeyPhrase, helpHidden, showQuickstart;
- (id)init {
if(!(self = [super init]))
return self;
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(dataStoreError)),
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(storeKeyPhrase)),
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(rememberKeyPhrase)),
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(forgetKeyPhrase)),
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickstart)),
nil]];
return self;
}
+ (OPConfig *)get {
return (OPConfig *)[super get];
}
@end

View File

@@ -0,0 +1,16 @@
//
// OPContentViewController.h
// MasterPassword
//
// Created by Maarten Billemont on 03/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "OPElementEntity.h"
@interface OPContentViewController : UIViewController
@property (nonatomic, weak) OPElementEntity *activeElement;
@end

View File

@@ -0,0 +1,22 @@
//
// OPContentViewController.m
// MasterPassword
//
// Created by Maarten Billemont on 03/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPContentViewController.h"
@implementation OPContentViewController
@synthesize activeElement = _activeElement;
#pragma mark - View lifecycle
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end

View File

@@ -0,0 +1,24 @@
//
// OPElementEntity.h
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface OPElementEntity : NSManagedObject
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *mpHashHex;
@property (nonatomic) int16_t type;
@property (nonatomic) int16_t uses;
@property (nonatomic) NSTimeInterval lastUsed;
- (void)use;
- (id)content;
@end

View File

@@ -0,0 +1,42 @@
//
// OPElementEntity.m
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPElementEntity.h"
@implementation OPElementEntity
@dynamic name;
@dynamic mpHashHex;
@dynamic type;
@dynamic uses;
@dynamic lastUsed;
- (void)use {
++self.uses;
self.lastUsed = [[NSDate date] timeIntervalSinceReferenceDate];
}
- (id)content {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Content implementation missing." userInfo:nil];
}
- (NSString *)description {
return [[self content] description];
}
- (NSString *)debugDescription {
return [NSString stringWithFormat:@"{%@: name=%@, mpHashHex=%@, type=%d, uses=%d, lastUsed=%@}",
NSStringFromClass([self class]), self.name, self.mpHashHex, self.type, self.uses, self.lastUsed];
}
@end

View File

@@ -0,0 +1,18 @@
//
// OPElementGeneratedEntity.h
// MasterPassword
//
// Created by Maarten Billemont on 16/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "OPElementEntity.h"
@interface OPElementGeneratedEntity : OPElementEntity
@property (nonatomic) int16_t counter;
@end

View File

@@ -0,0 +1,31 @@
//
// OPElementGeneratedEntity.m
// MasterPassword
//
// Created by Maarten Billemont on 16/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPElementGeneratedEntity.h"
#import "OPAppDelegate.h"
@implementation OPElementGeneratedEntity
@dynamic counter;
- (id)content {
assert(self.type & OPElementTypeClassCalculated);
if (![self.name length])
return nil;
if (self.type & OPElementTypeClassCalculated)
return OPCalculateContent(self.type, self.name, [OPAppDelegate get].keyPhrase, self.counter);
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"Unsupported type: %d", self.type] userInfo:nil];
}
@end

View File

@@ -0,0 +1,18 @@
//
// OPElementStoredEntity.h
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "OPElementEntity.h"
@interface OPElementStoredEntity : OPElementEntity
@property (nonatomic, retain) id contentObject;
@end

View File

@@ -0,0 +1,23 @@
//
// OPElementStoredEntity.m
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPElementStoredEntity.h"
@implementation OPElementStoredEntity
@dynamic contentObject;
- (id)content {
assert(self.type & OPElementTypeClassStored);
return self.contentObject;
}
@end

View File

@@ -0,0 +1,17 @@
//
// OPGuideViewController.h
// MasterPassword
//
// Created by Maarten Billemont on 30/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface OPGuideViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
- (IBAction)close;
@end

View File

@@ -0,0 +1,46 @@
//
// OPGuideViewController.m
// MasterPassword
//
// Created by Maarten Billemont on 30/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPGuideViewController.h"
#import "OPAppDelegate.h"
@implementation OPGuideViewController
@synthesize scrollView;
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)viewDidLoad {
[super viewDidLoad];
[UIUtils autoSizeContent:self.scrollView];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[OPConfig get].showQuickstart = [NSNumber numberWithBool:NO];
[[OPAppDelegate get] loadKeyPhrase];
}
- (void)viewDidUnload {
[self setScrollView:nil];
[super viewDidUnload];
}
- (IBAction)close {
[self.presentingViewController dismissModalViewControllerAnimated:YES];
}
@end

View File

@@ -0,0 +1,41 @@
//
// OPMainViewController.h
// MasterPassword
//
// Created by Maarten Billemont on 24/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import "OPTypeViewController.h"
#import "OPElementEntity.h"
#import "OPSearchDelegate.h"
@interface OPMainViewController : UIViewController <OPTypeDelegate, UITextFieldDelegate, UISearchBarDelegate, OPSearchResultsDelegate, UIWebViewDelegate>
@property (strong, nonatomic) OPElementEntity *activeElement;
@property (strong, nonatomic) IBOutlet OPSearchDelegate *searchResultsController;
@property (weak, nonatomic) IBOutlet UITextField *contentField;
@property (weak, nonatomic) IBOutlet UIButton *typeButton;
@property (weak, nonatomic) IBOutlet UIWebView *helpView;
@property (weak, nonatomic) IBOutlet UILabel *siteName;
@property (weak, nonatomic) IBOutlet UILabel *passwordCounter;
@property (weak, nonatomic) IBOutlet UIButton *passwordIncrementer;
@property (weak, nonatomic) IBOutlet UIButton *passwordEdit;
@property (weak, nonatomic) IBOutlet UIView *contentContainer;
@property (weak, nonatomic) IBOutlet UIView *helpContainer;
@property (weak, nonatomic) IBOutlet UIView *contentTipContainer;
@property (weak, nonatomic) IBOutlet UIView *alertContainer;
@property (weak, nonatomic) IBOutlet UILabel *alertTitle;
@property (weak, nonatomic) IBOutlet UITextView *alertBody;
@property (weak, nonatomic) IBOutlet UILabel *contentTipBody;
@property (weak, nonatomic) IBOutlet UIImageView *contentTipEditIcon;
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
- (IBAction)copyContent;
- (IBAction)incrementPasswordCounter;
- (IBAction)editPassword;
- (IBAction)toggleHelp;
- (void)toggleHelp:(BOOL)hidden;
- (IBAction)closeAlert;
@end

View File

@@ -0,0 +1,385 @@
//
// OPMainViewController.m
// MasterPassword
//
// Created by Maarten Billemont on 24/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import "OPMainViewController.h"
#import "OPAppDelegate.h"
#import "OPContentViewController.h"
#import "OPElementGeneratedEntity.h"
#import "OPElementStoredEntity.h"
#import <MobileCoreServices/MobileCoreServices.h>
@interface OPMainViewController (Private)
- (void)updateAnimated:(BOOL)animated;
- (void)updateWasAnimated:(BOOL)animated;
- (void)showContentTip:(NSString *)message withIcon:(UIImageView *)icon;
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message;
- (void)updateElement:(void (^)(void))updateElement;
@end
@implementation OPMainViewController
@synthesize activeElement = _activeElement;
@synthesize searchResultsController = _searchResultsController;
@synthesize typeButton = _typeButton;
@synthesize helpView = _helpView;
@synthesize siteName = _siteName;
@synthesize passwordCounter = _passwordCounter;
@synthesize passwordIncrementer = _passwordIncrementer;
@synthesize passwordEdit = _passwordEdit;
@synthesize contentContainer = _contentContainer;
@synthesize helpContainer = _helpContainer;
@synthesize contentTipContainer = _copiedContainer;
@synthesize alertContainer = _alertContainer;
@synthesize alertTitle = _alertTitle;
@synthesize alertBody = _alertBody;
@synthesize contentTipBody = _contentTipBody;
@synthesize contentTipEditIcon = _contentTipEditIcon;
@synthesize searchTipContainer = _searchTip;
@synthesize contentField = _contentField;
#pragma mark - View lifecycle
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad || interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:@"OP_Main_ChooseType"])
[[segue destinationViewController] setDelegate:self];
if ([[segue identifier] isEqualToString:@"OP_Main_Content"])
((OPContentViewController *)[segue destinationViewController]).activeElement = self.activeElement;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.searchTipContainer.hidden = NO;
if (!self.activeElement.name)
[UIView animateWithDuration:animated? 0.2f: 0 animations:^{
self.searchTipContainer.alpha = 1;
}];
[self toggleHelp:[[OPConfig get].helpHidden boolValue]];
[self updateAnimated:NO];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.searchTipContainer.hidden = YES;
}
- (void)viewDidLoad {
// Put the search tip on the window so it's above the nav bar.
CGRect newFrame = [self.navigationController.navigationBar convertRect:self.searchTipContainer.frame
fromView:self.searchTipContainer.superview];
[self.searchTipContainer removeFromSuperview];
[self.navigationController.navigationBar addSubview:self.searchTipContainer];
self.searchTipContainer.frame = newFrame;
self.searchTipContainer.hidden = YES;
// Because IB's edit button doesn't auto-toggle self.editable like editButtonItem does.
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
if (![OPAppDelegate get].keyPhrase) {
self.activeElement = nil;
[self updateAnimated:NO];
}
}];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidBecomeActiveNotification object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
if (![OPAppDelegate get].keyPhrase) {
self.activeElement = nil;
[self updateAnimated:NO];
}
}];
[self closeAlert];
[super viewDidLoad];
}
- (void)viewDidUnload {
[self setContentField:nil];
[self setTypeButton:nil];
[self setSearchResultsController:nil];
[self setHelpView:nil];
[self setSiteName:nil];
[self setPasswordCounter:nil];
[self setPasswordIncrementer:nil];
[self setPasswordEdit:nil];
[self setContentContainer:nil];
[self setHelpContainer:nil];
[self setContentTipContainer:nil];
[self setAlertContainer:nil];
[self setAlertTitle:nil];
[self setAlertBody:nil];
[self setContentTipBody:nil];
[self setContentTipEditIcon:nil];
[self setSearchTipContainer:nil];
[super viewDidUnload];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self updateAnimated:animated];
}
- (void)updateAnimated:(BOOL)animated {
[[OPAppDelegate get] saveContext];
if (animated)
[UIView animateWithDuration:0.2 animations:^{
[self updateWasAnimated:YES];
}];
else
[self updateWasAnimated:NO];
}
- (void)updateWasAnimated:(BOOL)animated {
NSUInteger chapter = self.activeElement? 2: 1;
[self.helpView loadRequest:
[NSURLRequest requestWithURL:
[NSURL URLWithString:[NSString stringWithFormat:@"#%d", chapter] relativeToURL:
[[NSBundle mainBundle] URLForResource:@"help" withExtension:@"html"]]]];
[self.helpView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setClass('%@');",
ClassNameFromOPElementType(self.activeElement.type)]];
self.siteName.text = self.activeElement.name;
self.passwordCounter.alpha = self.activeElement.type & OPElementTypeClassCalculated? 0.5f: 0;
self.passwordIncrementer.alpha = self.activeElement.type & OPElementTypeClassCalculated? 0.5f: 0;
self.passwordEdit.alpha = self.activeElement.type & OPElementTypeClassStored? 0.5f: 0;
[self.typeButton setTitle:NSStringFromOPElementType(self.activeElement.type)
forState:UIControlStateNormal];
self.typeButton.alpha = NSStringFromOPElementType(self.activeElement.type).length? 1: 0;
self.contentField.enabled = NO;
if ([self.activeElement isKindOfClass:[OPElementGeneratedEntity class]])
self.passwordCounter.text = [NSString stringWithFormat:@"%d", ((OPElementGeneratedEntity *) self.activeElement).counter];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *description = self.activeElement.description;
dispatch_async(dispatch_get_main_queue(), ^{
self.contentField.text = description;
});
});
}
- (void)showContentTip:(NSString *)message withIcon:(UIImageView *)icon {
self.contentTipBody.text = message;
icon.hidden = NO;
[UIView animateWithDuration:0.2f animations:^{
self.contentTipContainer.alpha = 1;
} completion:^(BOOL finished) {
if (!finished) {
icon.hidden = YES;
return;
}
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 5.0f * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[UIView animateWithDuration:0.2f animations:^{
self.contentTipContainer.alpha = 0;
} completion:^(BOOL finished) {
icon.hidden = YES;
}];
});
}];
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message {
self.alertTitle.text = title;
if ([self.alertBody.text length])
self.alertBody.text = [NSString stringWithFormat:@"%@\n\n---\n\n%@", self.alertBody.text, message];
else
self.alertBody.text = message;
[UIView animateWithDuration:0.2f animations:^{
self.alertContainer.alpha = 1;
}];
}
#pragma mark - Protocols
- (IBAction)copyContent {
if (!self.activeElement)
return;
[[UIPasteboard generalPasteboard] setValue:self.activeElement.content
forPasteboardType:(id)kUTTypeUTF8PlainText];
[self showContentTip:@"Copied!" withIcon:nil];
}
- (IBAction)incrementPasswordCounter {
if (![self.activeElement isKindOfClass:[OPElementGeneratedEntity class]])
// Not of a type that supports a password counter;
return;
[self updateElement:^{
++((OPElementGeneratedEntity *) self.activeElement).counter;
}];
}
- (void)updateElement:(void (^)(void))updateElement {
// Update password counter.
NSString *oldPassword = self.activeElement.description;
updateElement();
NSString *newPassword = self.activeElement.description;
[self updateAnimated:YES];
// Show new and old password.
if (oldPassword && ![oldPassword isEqualToString:newPassword])
[self showAlertWithTitle:@"Password Changed!" message:l(@"The password for %@ has changed.\n\n"
@"Don't forget to update the site with your new password! "
@"Your old password was:\n"
@"%@", self.activeElement.name, oldPassword)];
}
- (IBAction)editPassword {
if (self.activeElement.type & OPElementTypeClassStored) {
self.contentField.enabled = YES;
[self.contentField becomeFirstResponder];
}
}
- (IBAction)toggleHelp {
[UIView animateWithDuration:0.3f animations:^{
if (self.helpContainer.frame.origin.y < 400)
[self toggleHelp:YES];
else
[self toggleHelp:NO];
}];
}
- (void)toggleHelp:(BOOL)hidden {
if (hidden) {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 373);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 415);
[OPConfig get].helpHidden = [NSNumber numberWithBool:YES];
} else {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 175);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 216);
[OPConfig get].helpHidden = [NSNumber numberWithBool:NO];
}
}
- (IBAction)closeAlert {
[UIView animateWithDuration:0.3f animations:^{
self.alertContainer.alpha = 0;
} completion:^(BOOL finished) {
self.alertBody.text = nil;
}];
}
- (void)didSelectType:(OPElementType)type {
[self updateElement:^{
// Update password type.
if (ClassFromOPElementType(type) != ClassFromOPElementType(self.activeElement.type)) {
// Type requires a different class of element. Recreate the element.
OPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:ClassNameFromOPElementType(type)
inManagedObjectContext:[OPAppDelegate managedObjectContext]];
newElement.name = self.activeElement.name;
newElement.mpHashHex = self.activeElement.mpHashHex;
newElement.uses = self.activeElement.uses;
newElement.lastUsed = self.activeElement.lastUsed;
[[OPAppDelegate managedObjectContext] deleteObject:self.activeElement];
self.activeElement = newElement;
}
self.activeElement.type = type;
if (type & OPElementTypeClassStored && ![self.activeElement.description length])
[self showContentTip:@"Tap to set a password." withIcon:self.contentTipEditIcon];
}];
}
- (void)didSelectElement:(OPElementEntity *)element {
self.activeElement = element;
[self.activeElement use];
[self.searchDisplayController setActive:NO animated:YES];
self.searchDisplayController.searchBar.text = self.activeElement.name;
[self updateAnimated:YES];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self updateAnimated:YES];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if (textField == self.contentField)
[self.contentField resignFirstResponder];
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (textField == self.contentField) {
self.contentField.enabled = NO;
if (![self.activeElement isKindOfClass:[OPElementStoredEntity class]])
// Not of a type whose content can be edited.
return;
if ([((OPElementStoredEntity *) self.activeElement).contentObject isEqual:self.contentField.text])
// Content hasn't changed.
return;
[self updateElement:^{
((OPElementStoredEntity *) self.activeElement).contentObject = self.contentField.text;
}];
}
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
[[UIApplication sharedApplication] openURL:[request URL]];
return NO;
}
return YES;
}
@end

View File

@@ -0,0 +1,15 @@
//
// OPRecentViewController.h
// MasterPassword
//
// Created by Maarten Billemont on 27/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface OPRecentViewController : UITableViewController
@property(nonatomic,retain) IBOutlet UITableView *tableView;
@end

View File

@@ -0,0 +1,20 @@
//
// OPRecentViewController.m
// MasterPassword
//
// Created by Maarten Billemont on 27/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import "OPRecentViewController.h"
@implementation OPRecentViewController
@dynamic tableView;
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
@end

View File

@@ -0,0 +1,26 @@
//
// OPSearchDelegate.h
// MasterPassword
//
// Created by Maarten Billemont on 04/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "OPElementEntity.h"
@protocol OPSearchResultsDelegate <NSObject>
- (void)didSelectElement:(OPElementEntity *)element;
@end
@interface OPSearchDelegate : NSObject <UITableViewDelegate, UITableViewDataSource, UISearchDisplayDelegate, NSFetchedResultsControllerDelegate>
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
@property (weak, nonatomic) IBOutlet id<OPSearchResultsDelegate> delegate;
@property (weak, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
@end

View File

@@ -0,0 +1,243 @@
//
// OPSearchDelegate.m
// MasterPassword
//
// Created by Maarten Billemont on 04/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPSearchDelegate.h"
#import "OPAppDelegate.h"
#import "OPElementGeneratedEntity.h"
@interface OPSearchDelegate (Private)
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath;
- (void)update;
@end
@implementation OPSearchDelegate
@synthesize fetchedResultsController;
@synthesize delegate;
@synthesize searchDisplayController;
@synthesize searchTipContainer;
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
self.searchDisplayController.searchBar.text = @"";
self.searchDisplayController.searchBar.prompt = @"Enter the site's domain name (eg. apple.com):";
[UIView animateWithDuration:0.2f animations:^{
self.searchTipContainer.alpha = 0;
}];
[self update];
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
self.searchDisplayController.searchBar.prompt = nil;
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView {
tableView.backgroundColor = [UIColor blackColor];
tableView.rowHeight = 34.0f;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
}
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
[tableView setEditing:self.searchDisplayController.searchContentsController.editing animated:NO];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
[self update];
return YES;
}
- (void)update {
NSString *query = self.searchDisplayController.searchBar.text;
if (!query)
query = @"";
NSFetchRequest *fetchRequest = [[OPAppDelegate get].managedObjectModel
fetchRequestFromTemplateWithName:@"OPSearchElement"
substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:
query, @"query",
[OPAppDelegate get].keyPhraseHashHex, @"mpHashHex",
nil]];
[fetchRequest setSortDescriptors:
[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[OPAppDelegate managedObjectContext]
sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController.delegate = self;
NSError *error;
if (![self.fetchedResultsController performFetch:&error])
err(@"Couldn't fetch elements: %@", error);
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.searchDisplayController.searchResultsTableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath]
inTableView:tableView
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
UITableView *tableView = self.searchDisplayController.searchResultsTableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.searchDisplayController.searchResultsTableView endUpdates];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.fetchedResultsController sections] count] + 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == [self numberOfSectionsInTableView:tableView] - 1)
return 1;
return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"OPElementSearch"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"OPElementSearch"];
UIImageView *backgroundImageView = [[UIImageView alloc] initWithImage:[[UIImage imageNamed:@"ui_list_middle"] resizableImageWithCapInsets:UIEdgeInsetsMake(5, 5, 5, 5)]];
backgroundImageView.frame = CGRectMake(-5, 0, 330, 34);
UIView *backgroundView = [[UIView alloc] initWithFrame:cell.frame];
[backgroundView addSubview:backgroundImageView];
cell.backgroundView = backgroundView;
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.backgroundColor = [UIColor clearColor];
cell.detailTextLabel.textColor = [UIColor lightGrayColor];
}
[self configureCell:cell inTableView:tableView atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)cell inTableView:(UITableView *)tableView atIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section < [[self.fetchedResultsController sections] count]) {
OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = element.name;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%d", element.uses];
} else {
// "New" section
cell.textLabel.text = self.searchDisplayController.searchBar.text;
cell.detailTextLabel.text = @"New";
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
OPElementEntity *element;
if (indexPath.section < [[self.fetchedResultsController sections] count])
element = [self.fetchedResultsController objectAtIndexPath:indexPath];
else {
// "New" section.
element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([OPElementGeneratedEntity class])
inManagedObjectContext:[OPAppDelegate managedObjectContext]];
assert([element isKindOfClass:ClassFromOPElementType(element.type)]);
element.name = self.searchDisplayController.searchBar.text;
element.mpHashHex = [OPAppDelegate get].keyPhraseHashHex;
}
[self.delegate didSelectElement:element];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (--section == -1)
return @"";
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [self.fetchedResultsController sectionIndexTitles];
}
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == [[self.fetchedResultsController sections] count])
// "New" section.
return;
if (editingStyle == UITableViewCellEditingStyleDelete) {
OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
[[OPAppDelegate managedObjectContext] deleteObject:element];
}
}
@end

View File

@@ -0,0 +1,21 @@
//
// OPTypeViewController.h
// MasterPassword
//
// Created by Maarten Billemont on 27/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import <UIKit/UIKit.h>
@protocol OPTypeDelegate <NSObject>
- (void)didSelectType:(OPElementType)type;
@end
@interface OPTypeViewController : UITableViewController
@property (nonatomic, weak) id<OPTypeDelegate> delegate;
@end

View File

@@ -0,0 +1,86 @@
//
// OPTypeViewController.m
// MasterPassword
//
// Created by Maarten Billemont on 27/11/11.
// Copyright (c) 2011 Lyndir. All rights reserved.
//
#import "OPTypeViewController.h"
@implementation OPTypeViewController
@synthesize delegate;
#pragma mark - View lifecycle
- (void)viewDidLoad {
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]];
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
assert(self.navigationController.topViewController == self);
OPElementType type;
switch (indexPath.section) {
case 0: {
// Calculated
switch (indexPath.row) {
case 0:
type = OPElementTypeCalculatedLong;
break;
case 1:
type = OPElementTypeCalculatedMedium;
break;
case 2:
type = OPElementTypeCalculatedShort;
break;
case 3:
type = OPElementTypeCalculatedBasic;
break;
case 4:
type = OPElementTypeCalculatedPIN;
break;
default:
[NSException raise:NSInternalInconsistencyException
format:@"Unsupported row: %d, when selecting calculated element type.", indexPath.row];
}
break;
}
case 1: {
// Stored
switch (indexPath.row) {
case 0:
type = OPElementTypeStoredPersonal;
break;
case 1:
type = OPElementTypeStoredDevicePrivate;
break;
default:
[NSException raise:NSInternalInconsistencyException
format:@"Unsupported row: %d, when selecting stored element type.", indexPath.row];
}
break;
}
default:
[NSException raise:NSInternalInconsistencyException
format:@"Unsupported section: %d, when selecting element type.", indexPath.section];
}
[delegate didSelectType:type];
[self.navigationController popViewControllerAnimated:YES];
}
@end

36
MasterPassword/OPTypes.h Normal file
View File

@@ -0,0 +1,36 @@
//
// OPTypes.h
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import <Foundation/Foundation.h>
typedef enum {
OPElementContentTypePassword,
OPElementContentTypeNote,
OPElementContentTypePicture,
} OPElementContentType;
typedef enum {
OPElementTypeClassCalculated = 2 << 7,
OPElementTypeClassStored = 2 << 8,
} OPElementTypeClass;
typedef enum {
OPElementTypeCalculatedLong = OPElementTypeClassCalculated | 0x01,
OPElementTypeCalculatedMedium = OPElementTypeClassCalculated | 0x02,
OPElementTypeCalculatedShort = OPElementTypeClassCalculated | 0x03,
OPElementTypeCalculatedBasic = OPElementTypeClassCalculated | 0x04,
OPElementTypeCalculatedPIN = OPElementTypeClassCalculated | 0x05,
OPElementTypeStoredPersonal = OPElementTypeClassStored | 0x01,
OPElementTypeStoredDevicePrivate = OPElementTypeClassStored | 0x02,
} OPElementType;
NSString *NSStringFromOPElementType(OPElementType type);
NSString *ClassNameFromOPElementType(OPElementType type);
Class ClassFromOPElementType(OPElementType type);
NSString *OPCalculateContent(OPElementType type, NSString *name, NSString *keyPhrase, int counter);

115
MasterPassword/OPTypes.m Normal file
View File

@@ -0,0 +1,115 @@
//
// OPTypes.m
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#import "OPTypes.h"
#import "OPElementGeneratedEntity.h"
#import "OPElementStoredEntity.h"
NSString *NSStringFromOPElementType(OPElementType type) {
if (!type)
return nil;
switch (type) {
case OPElementTypeCalculatedLong:
return @"Long Password";
case OPElementTypeCalculatedMedium:
return @"Medium Password";
case OPElementTypeCalculatedShort:
return @"Short Password";
case OPElementTypeCalculatedBasic:
return @"Basic Password";
case OPElementTypeCalculatedPIN:
return @"PIN";
case OPElementTypeStoredPersonal:
return @"Personal Password";
case OPElementTypeStoredDevicePrivate:
return @"Device Private Password";
default:
[NSException raise:NSInternalInconsistencyException format:@"Type not supported: %d", type];
}
}
Class ClassFromOPElementType(OPElementType type) {
if (!type)
return nil;
switch (type) {
case OPElementTypeCalculatedLong:
return [OPElementGeneratedEntity class];
case OPElementTypeCalculatedMedium:
return [OPElementGeneratedEntity class];
case OPElementTypeCalculatedShort:
return [OPElementGeneratedEntity class];
case OPElementTypeCalculatedBasic:
return [OPElementGeneratedEntity class];
case OPElementTypeCalculatedPIN:
return [OPElementGeneratedEntity class];
case OPElementTypeStoredPersonal:
return [OPElementStoredEntity class];
case OPElementTypeStoredDevicePrivate:
return [OPElementStoredEntity class];
default:
[NSException raise:NSInternalInconsistencyException format:@"Type not supported: %d", type];
}
}
NSString *ClassNameFromOPElementType(OPElementType type) {
return NSStringFromClass(ClassFromOPElementType(type));
}
static NSDictionary *OPTypes_ciphers = nil;
NSString *OPCalculateContent(OPElementType type, NSString *name, NSString *keyPhrase, int counter) {
assert(type & OPElementTypeClassCalculated);
if (OPTypes_ciphers == nil)
OPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ciphers"
withExtension:@"plist"]];
// Determine the hash whose bytes will be used for calculating a password: md4(name-keyPhrase)
assert(name && keyPhrase);
NSData *keyHash = [[NSString stringWithFormat:@"%@-%@-%d", name, keyPhrase, counter] hashWith:PearlDigestSHA1];
const char *keyBytes = keyHash.bytes;
// Determine the cipher from the first hash byte.
assert([keyHash length]);
NSArray *typeCiphers = [[OPTypes_ciphers valueForKey:ClassNameFromOPElementType(type)]
valueForKey:NSStringFromOPElementType(type)];
NSString *cipher = [typeCiphers objectAtIndex:keyBytes[0] % [typeCiphers count]];
// Encode the content, character by character, using subsequent hash bytes and the cipher.
assert([keyHash length] >= [cipher length] + 1);
NSMutableString *content = [NSMutableString stringWithCapacity:[cipher length]];
for (NSUInteger c = 0; c < [cipher length]; ++c) {
const char keyByte = keyBytes[c + 1];
NSString *cipherClass = [cipher substringWithRange:NSMakeRange(c, 1)];
NSString *cipherClassCharacters = [[OPTypes_ciphers valueForKey:@"OPCharacterClasses"] valueForKey:cipherClass];
[content appendString:[cipherClassCharacters substringWithRange:NSMakeRange(keyByte % [cipherClassCharacters length], 1)]];
}
return content;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Some files were not shown because too many files have changed in this diff Show More