OnePassword -> MasterPassword
BIN
MasterPassword/.OPMainViewController.h.swk
Normal file
BIN
MasterPassword/.OPMainViewController.h.swl
Normal file
BIN
MasterPassword/.OPMainViewController.h.swm
Normal file
BIN
MasterPassword/.OPMainViewController.h.swn
Normal file
BIN
MasterPassword/.OPMainViewController.h.swo
Normal file
BIN
MasterPassword/.OPTypes.m.swn
Normal file
BIN
MasterPassword/.OPTypes.m.swo
Normal file
89
MasterPassword/MainStoryboard_iPad.storyboard
Normal 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>
|
780
MasterPassword/MainStoryboard_iPhone.storyboard
Normal 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>
|
75
MasterPassword/MasterPassword-Info.plist
Normal 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>
|
26
MasterPassword/MasterPassword-Prefix.pch
Normal 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"
|
@@ -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>
|
@@ -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>
|
30
MasterPassword/OPAppDelegate.h
Normal 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
|
412
MasterPassword/OPAppDelegate.m
Normal 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
@@ -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
@@ -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
|
16
MasterPassword/OPContentViewController.h
Normal 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
|
22
MasterPassword/OPContentViewController.m
Normal 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
|
24
MasterPassword/OPElementEntity.h
Normal 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
|
42
MasterPassword/OPElementEntity.m
Normal 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
|
18
MasterPassword/OPElementGeneratedEntity.h
Normal 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
|
31
MasterPassword/OPElementGeneratedEntity.m
Normal 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
|
18
MasterPassword/OPElementStoredEntity.h
Normal 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
|
23
MasterPassword/OPElementStoredEntity.m
Normal 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
|
17
MasterPassword/OPGuideViewController.h
Normal 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
|
46
MasterPassword/OPGuideViewController.m
Normal 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
|
41
MasterPassword/OPMainViewController.h
Normal 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
|
385
MasterPassword/OPMainViewController.m
Normal 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
|
15
MasterPassword/OPRecentViewController.h
Normal 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
|
20
MasterPassword/OPRecentViewController.m
Normal 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
|
26
MasterPassword/OPSearchDelegate.h
Normal 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
|
243
MasterPassword/OPSearchDelegate.m
Normal 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
|
21
MasterPassword/OPTypeViewController.h
Normal 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
|
86
MasterPassword/OPTypeViewController.m
Normal 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
@@ -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
@@ -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;
|
||||
}
|
BIN
MasterPassword/Resources/Automaton/ui_background.png
Normal file
After Width: | Height: | Size: 1023 B |
BIN
MasterPassword/Resources/Automaton/ui_background@2x.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
MasterPassword/Resources/Automaton/ui_box_checked.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
MasterPassword/Resources/Automaton/ui_box_checked@2x.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
MasterPassword/Resources/Automaton/ui_box_empty.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
MasterPassword/Resources/Automaton/ui_box_empty@2x.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
MasterPassword/Resources/Automaton/ui_box_filled.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
MasterPassword/Resources/Automaton/ui_box_filled@2x.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_green_large.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_green_large@2x.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_green_small.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_green_small@2x.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_red_large.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_red_large@2x.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_red_small.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_red_small@2x.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_standard_large.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 3.3 KiB |
BIN
MasterPassword/Resources/Automaton/ui_button_standard_small.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 3.0 KiB |
BIN
MasterPassword/Resources/Automaton/ui_dropdown.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
MasterPassword/Resources/Automaton/ui_dropdown@2x.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_arrow.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_arrow@2x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_arrow_active.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_arrow_active@2x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_first.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_first@2x.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_last.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_last@2x.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_middle.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
MasterPassword/Resources/Automaton/ui_list_middle@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
MasterPassword/Resources/Automaton/ui_navbar@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
MasterPassword/Resources/Automaton/ui_navbar_back.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
MasterPassword/Resources/Automaton/ui_navbar_back@2x.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
MasterPassword/Resources/Automaton/ui_navbar_button.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_navbar_button@2x.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
MasterPassword/Resources/Automaton/ui_navbar_container.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
MasterPassword/Resources/Automaton/ui_navbar_container@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
MasterPassword/Resources/Automaton/ui_panel_container.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
MasterPassword/Resources/Automaton/ui_panel_container@2x.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
MasterPassword/Resources/Automaton/ui_panel_display.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
MasterPassword/Resources/Automaton/ui_panel_display@2x.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
BIN
MasterPassword/Resources/Automaton/ui_slider-knob_container.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.4 KiB |
BIN
MasterPassword/Resources/Automaton/ui_slider-knob_fill_dark.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
BIN
MasterPassword/Resources/Automaton/ui_slider-knob_fill_light.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 3.5 KiB |