Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b997528c9 | ||
|
|
04a6c8e68d | ||
|
|
0e8e4dc06d | ||
|
|
8b91c2a0b8 | ||
|
|
e967affddb | ||
|
|
dea7434bd4 | ||
|
|
1da63e450d | ||
|
|
029d240999 | ||
|
|
110f7069e1 | ||
|
|
d77cde1929 |
5
.gitignore
vendored
@@ -20,6 +20,11 @@
|
||||
!/*.xcodeproj/project.xcworkspace/*
|
||||
/*.xcodeproj/project.xcworkspace/xcuserdata
|
||||
|
||||
# Media
|
||||
Press/Background.png
|
||||
Press/Front-Page.png
|
||||
Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
|
||||
|
||||
# IPA
|
||||
/sendipa/*
|
||||
!/sendipa/sendipa.conf
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.1.2</string>
|
||||
<string>1.1.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
@@ -25,7 +25,7 @@
|
||||
<string>iPhoneOS</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>0101.02.00</string>
|
||||
<string>0101.03.00</string>
|
||||
<key>CrashlyticsAPIKey</key>
|
||||
<string>0d10c90776f5ef5acd01ddbeaca9a6cba4814560</string>
|
||||
<key>DTCompiler</key>
|
||||
|
||||
2
External/Pearl
vendored
@@ -20,6 +20,11 @@
|
||||
DA30E9D415722EF400A68B4C /* Pearl-UIKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */; };
|
||||
DA30E9D715723E6900A68B4C /* PearlLazy.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9D515723E6900A68B4C /* PearlLazy.h */; };
|
||||
DA30E9D815723E6900A68B4C /* PearlLazy.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9D615723E6900A68B4C /* PearlLazy.m */; };
|
||||
DA3EF17B15A47744003ABF4E /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */; };
|
||||
DA3EF17C15A47744003ABF4E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA48147E415C00F98B1E /* UIKit.framework */; };
|
||||
DA3EF17D15A47744003ABF4E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
|
||||
DA3EF18315A47744003ABF4E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DA3EF18115A47744003ABF4E /* InfoPlist.strings */; };
|
||||
DA3EF18615A47744003ABF4E /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3EF18515A47744003ABF4E /* Tests.m */; };
|
||||
DA40C2611586099D0079CE6E /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA40C2601586099D0079CE6E /* MPUserEntity.m */; };
|
||||
DA40C2641586099E0079CE6E /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA40C2631586099E0079CE6E /* MPElementEntity.m */; };
|
||||
DA40C2671586099E0079CE6E /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA40C2661586099E0079CE6E /* MPElementGeneratedEntity.m */; };
|
||||
@@ -828,6 +833,13 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
DA3EF19D15A47AEB003ABF4E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = DA5BFA43147E415C00F98B1E;
|
||||
remoteInfo = MasterPassword;
|
||||
};
|
||||
DA4DA1D71564470200F6F596 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = DA79A9BD1557DDC700BAA07A /* scrypt.xcodeproj */;
|
||||
@@ -893,6 +905,13 @@
|
||||
DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Pearl-UIKit.m"; sourceTree = "<group>"; };
|
||||
DA30E9D515723E6900A68B4C /* PearlLazy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlLazy.h; sourceTree = "<group>"; };
|
||||
DA30E9D615723E6900A68B4C /* PearlLazy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlLazy.m; sourceTree = "<group>"; };
|
||||
DA3EF17915A47744003ABF4E /* Tests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.octest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
DA3EF18015A47744003ABF4E /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; };
|
||||
DA3EF18215A47744003ABF4E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
DA3EF18415A47744003ABF4E /* Tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Tests.h; sourceTree = "<group>"; };
|
||||
DA3EF18515A47744003ABF4E /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; };
|
||||
DA3EF18715A47744003ABF4E /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; };
|
||||
DA40C25F1586099D0079CE6E /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = "<group>"; };
|
||||
DA40C2601586099D0079CE6E /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; };
|
||||
DA40C2621586099E0079CE6E /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
|
||||
@@ -1787,6 +1806,16 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
DA3EF17515A47744003ABF4E /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DA3EF17B15A47744003ABF4E /* SenTestingKit.framework in Frameworks */,
|
||||
DA3EF17C15A47744003ABF4E /* UIKit.framework in Frameworks */,
|
||||
DA3EF17D15A47744003ABF4E /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DA4425C81557BED40052177D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -1874,6 +1903,26 @@
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
DA3EF17E15A47744003ABF4E /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA3EF18415A47744003ABF4E /* Tests.h */,
|
||||
DA3EF18515A47744003ABF4E /* Tests.m */,
|
||||
DA3EF17F15A47744003ABF4E /* Supporting Files */,
|
||||
);
|
||||
path = Tests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA3EF17F15A47744003ABF4E /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DA3EF18015A47744003ABF4E /* Tests-Info.plist */,
|
||||
DA3EF18115A47744003ABF4E /* InfoPlist.strings */,
|
||||
DA3EF18715A47744003ABF4E /* Tests-Prefix.pch */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DA4425D71557BF260052177D /* iCloudStoreManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -1900,6 +1949,7 @@
|
||||
DAD3127315528CD200A3F9ED /* Localytics */,
|
||||
DA4425D71557BF260052177D /* iCloudStoreManager */,
|
||||
DA829E5D15984812002417D3 /* FontReplacer */,
|
||||
DA3EF17E15A47744003ABF4E /* Tests */,
|
||||
DA5BFA47147E415C00F98B1E /* Frameworks */,
|
||||
DA5BFA45147E415C00F98B1E /* Products */,
|
||||
);
|
||||
@@ -1916,6 +1966,7 @@
|
||||
DAD3127115528CD200A3F9ED /* libLocalytics.a */,
|
||||
DA4425CB1557BED40052177D /* libiCloudStoreManager.a */,
|
||||
DA829E51159847E0002417D3 /* libFontReplacer.a */,
|
||||
DA3EF17915A47744003ABF4E /* Tests.octest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -1935,6 +1986,7 @@
|
||||
DA5BFA4A147E415C00F98B1E /* Foundation.framework */,
|
||||
DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */,
|
||||
DA5BFA4E147E415C00F98B1E /* CoreData.framework */,
|
||||
DA3EF17A15A47744003ABF4E /* SenTestingKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -3222,6 +3274,25 @@
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
DA3EF17815A47744003ABF4E /* Tests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DA3EF18815A47744003ABF4E /* Build configuration list for PBXNativeTarget "Tests" */;
|
||||
buildPhases = (
|
||||
DA3EF17415A47744003ABF4E /* Sources */,
|
||||
DA3EF17515A47744003ABF4E /* Frameworks */,
|
||||
DA3EF17615A47744003ABF4E /* Resources */,
|
||||
DA3EF17715A47744003ABF4E /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
DA3EF19E15A47AEB003ABF4E /* PBXTargetDependency */,
|
||||
);
|
||||
name = Tests;
|
||||
productName = Tests;
|
||||
productReference = DA3EF17915A47744003ABF4E /* Tests.octest */;
|
||||
productType = "com.apple.product-type.bundle";
|
||||
};
|
||||
DA4425CA1557BED40052177D /* iCloudStoreManager */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = DA4425D31557BED40052177D /* Build configuration list for PBXNativeTarget "iCloudStoreManager" */;
|
||||
@@ -3400,6 +3471,7 @@
|
||||
DAD3127015528CD200A3F9ED /* Localytics */,
|
||||
DA4425CA1557BED40052177D /* iCloudStoreManager */,
|
||||
DA829E50159847E0002417D3 /* FontReplacer */,
|
||||
DA3EF17815A47744003ABF4E /* Tests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -3429,6 +3501,14 @@
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
DA3EF17615A47744003ABF4E /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DA3EF18315A47744003ABF4E /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DA5BFA42147E415C00F98B1E /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -4074,6 +4154,19 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
DA3EF17715A47744003ABF4E /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# Run the unit tests in this test bundle.\n\"${SYSTEM_DEVELOPER_DIR}/Tools/RunUnitTests\"\n";
|
||||
};
|
||||
DA6556E314D55F3000841C99 /* Run Script: GIT version -> Info.plist */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -4107,6 +4200,14 @@
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
DA3EF17415A47744003ABF4E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DA3EF18615A47744003ABF4E /* Tests.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
DA4425C71557BED40052177D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -4252,6 +4353,11 @@
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
DA3EF19E15A47AEB003ABF4E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = DA5BFA43147E415C00F98B1E /* MasterPassword */;
|
||||
targetProxy = DA3EF19D15A47AEB003ABF4E /* PBXContainerItemProxy */;
|
||||
};
|
||||
DA4DA1D81564470200F6F596 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = "Makefile-scrypt";
|
||||
@@ -4270,6 +4376,14 @@
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
DA3EF18115A47744003ABF4E /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
DA3EF18215A47744003ABF4E /* en */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DAB8D43F15036BCF00CED3BC /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
@@ -4289,6 +4403,88 @@
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
DA3EF18915A47744003ABF4E /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MasterPassword.app/MasterPassword";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(DEVELOPER_LIBRARY_DIR)/Frameworks",
|
||||
"\"$(SRCROOT)/Crashlytics\"",
|
||||
);
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch";
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
INFOPLIST_FILE = "Tests/Tests-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.1;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = octest;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
DA3EF18A15A47744003ABF4E /* AdHoc */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MasterPassword.app/MasterPassword";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(DEVELOPER_LIBRARY_DIR)/Frameworks",
|
||||
"\"$(SRCROOT)/Crashlytics\"",
|
||||
);
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch";
|
||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Tests/Tests-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.1;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WRAPPER_EXTENSION = octest;
|
||||
};
|
||||
name = AdHoc;
|
||||
};
|
||||
DA3EF18B15A47744003ABF4E /* AppStore */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = "$(ARCHS_STANDARD_32_BIT)";
|
||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MasterPassword.app/MasterPassword";
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||
"$(DEVELOPER_LIBRARY_DIR)/Frameworks",
|
||||
"\"$(SRCROOT)/Crashlytics\"",
|
||||
);
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch";
|
||||
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "Tests/Tests-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 5.1;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WRAPPER_EXTENSION = octest;
|
||||
};
|
||||
name = AppStore;
|
||||
};
|
||||
DA4425D41557BED40052177D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@@ -4757,6 +4953,15 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
DA3EF18815A47744003ABF4E /* Build configuration list for PBXNativeTarget "Tests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
DA3EF18915A47744003ABF4E /* Debug */,
|
||||
DA3EF18A15A47744003ABF4E /* AdHoc */,
|
||||
DA3EF18B15A47744003ABF4E /* AppStore */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
};
|
||||
DA4425D31557BED40052177D /* Build configuration list for PBXNativeTarget "iCloudStoreManager" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
||||
@@ -28,6 +28,16 @@
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "DA3EF17815A47744003ABF4E"
|
||||
BuildableName = "Tests.octest"
|
||||
BlueprintName = "Tests"
|
||||
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
@@ -44,7 +54,7 @@
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "AppStore"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
|
||||
49
MasterPassword/Java/masterpassword-algorithm/pom.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password Algorithm Implementation</name>
|
||||
<description>The implementation of the Master Password algorithm</description>
|
||||
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-system</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.opal</groupId>
|
||||
<artifactId>opal-crypto</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EXTERNAL DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>net.sf.plist</groupId>
|
||||
<artifactId>property-list</artifactId>
|
||||
<version>svn-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lambdaworks</groupId>
|
||||
<artifactId>scrypt</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public enum MPElementFeature {
|
||||
|
||||
/** Export the key-protected content data. */
|
||||
ExportContent,
|
||||
/** Never export content. */
|
||||
DevicePrivate,
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public enum MPElementType {
|
||||
|
||||
GeneratedMaximum( "Maximum Security Password", "Maximum", "20 characters, contains symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedLong( "Long Password", "Long", "Copy-friendly, 14 characters, contains symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedMedium( "Medium Password", "Medium", "Copy-friendly, 8 characters, contains symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedShort( "Short Password", "Short", "Copy-friendly, 4 characters, no symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedBasic( "Basic Password", "Basic", "8 characters, no symbols.", MPElementTypeClass.Generated ),
|
||||
GeneratedPIN( "PIN", "PIN", "4 numbers.", MPElementTypeClass.Generated ),
|
||||
|
||||
StoredPersonal( "Personal Password", "Personal", "AES-encrypted, exportable.", MPElementTypeClass.Stored, MPElementFeature.ExportContent ),
|
||||
StoredDevicePrivate( "Device Private Password", "Private", "AES-encrypted, not exported.", MPElementTypeClass.Stored, MPElementFeature.DevicePrivate );
|
||||
|
||||
static final Logger logger = Logger.get( MPElementType.class );
|
||||
|
||||
private final MPElementTypeClass typeClass;
|
||||
private final Set<MPElementFeature> typeFeatures;
|
||||
private final String name;
|
||||
private final String shortName;
|
||||
private final String description;
|
||||
|
||||
MPElementType(final String name, final String shortName, final String description, final MPElementTypeClass typeClass, final MPElementFeature... typeFeatures) {
|
||||
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
this.typeClass = typeClass;
|
||||
this.description = description;
|
||||
|
||||
ImmutableSet.Builder<MPElementFeature> typeFeaturesBuilder = ImmutableSet.builder();
|
||||
for (final MPElementFeature typeFeature : typeFeatures)
|
||||
typeFeaturesBuilder.add( typeFeature );
|
||||
this.typeFeatures = typeFeaturesBuilder.build();
|
||||
}
|
||||
|
||||
public MPElementTypeClass getTypeClass() {
|
||||
|
||||
return typeClass;
|
||||
}
|
||||
|
||||
public Set<MPElementFeature> getTypeFeatures() {
|
||||
|
||||
return typeFeatures;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getShortName() {
|
||||
|
||||
return shortName;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
public static MPElementType forName(final String name) {
|
||||
|
||||
for (final MPElementType type : values())
|
||||
if (type.getName().equals( name ))
|
||||
return type;
|
||||
|
||||
throw logger.bug( "Element type not known: %s", name );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import com.lyndir.lhunath.masterpassword.entity.*;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public enum MPElementTypeClass {
|
||||
|
||||
Generated(MPElementGeneratedEntity.class),
|
||||
Stored(MPElementStoredEntity.class);
|
||||
|
||||
private final Class<? extends MPElementEntity> entityClass;
|
||||
|
||||
MPElementTypeClass(final Class<? extends MPElementEntity> entityClass) {
|
||||
|
||||
this.entityClass = entityClass;
|
||||
}
|
||||
|
||||
public Class<? extends MPElementEntity> getEntityClass() {
|
||||
|
||||
return entityClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPTemplate extends MetaObject {
|
||||
|
||||
private final List<MPTemplateCharacterClass> template;
|
||||
|
||||
public MPTemplate(final String template, final Map<Character, MPTemplateCharacterClass> characterClasses) {
|
||||
|
||||
ImmutableList.Builder<MPTemplateCharacterClass> builder = ImmutableList.<MPTemplateCharacterClass>builder();
|
||||
for (int i = 0; i < template.length(); ++i)
|
||||
builder.add( characterClasses.get( template.charAt( i ) ) );
|
||||
|
||||
this.template = builder.build();
|
||||
}
|
||||
|
||||
public MPTemplate(final List<MPTemplateCharacterClass> template) {
|
||||
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public MPTemplateCharacterClass getCharacterClassAtIndex(final int index) {
|
||||
|
||||
return template.get( index );
|
||||
}
|
||||
|
||||
public int length() {
|
||||
|
||||
return template.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
import com.lyndir.lhunath.opal.system.util.ObjectMeta;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPTemplateCharacterClass extends MetaObject {
|
||||
|
||||
private final char identifier;
|
||||
@ObjectMeta(useFor = { })
|
||||
private final char[] characters;
|
||||
|
||||
public MPTemplateCharacterClass(final char identifier, final char[] characters) {
|
||||
|
||||
this.identifier = identifier;
|
||||
this.characters = characters;
|
||||
}
|
||||
|
||||
public char getIdentifier() {
|
||||
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public char getCharacterAtRollingIndex(final int index) {
|
||||
|
||||
return characters[index % characters.length];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.Closeables;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.lhunath.opal.system.util.MetaObject;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.sf.plist.*;
|
||||
import net.sf.plist.io.PropertyListException;
|
||||
import net.sf.plist.io.PropertyListParser;
|
||||
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPTemplates extends MetaObject {
|
||||
|
||||
static final Logger logger = Logger.get( MPTemplates.class );
|
||||
|
||||
private final Map<MPElementType, List<MPTemplate>> templates;
|
||||
|
||||
public MPTemplates(final Map<MPElementType, List<MPTemplate>> templates) {
|
||||
|
||||
this.templates = templates;
|
||||
}
|
||||
|
||||
public static MPTemplates loadFromPList(final String templateResource) {
|
||||
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
InputStream templateStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( templateResource );
|
||||
try {
|
||||
NSObject plistObject = PropertyListParser.parse( templateStream );
|
||||
Preconditions.checkState( NSDictionary.class.isAssignableFrom( plistObject.getClass() ) );
|
||||
NSDictionary plist = (NSDictionary) plistObject;
|
||||
|
||||
NSDictionary characterClassesDict = (NSDictionary) plist.get( "MPCharacterClasses" );
|
||||
NSDictionary templatesDict = (NSDictionary) plist.get( "MPElementGeneratedEntity" );
|
||||
|
||||
ImmutableMap.Builder<Character, MPTemplateCharacterClass> characterClassesBuilder = ImmutableMap.builder();
|
||||
for (final Map.Entry<String, NSObject> characterClassEntry : characterClassesDict.entrySet()) {
|
||||
String key = characterClassEntry.getKey();
|
||||
NSObject value = characterClassEntry.getValue();
|
||||
Preconditions.checkState( key.length() == 1 );
|
||||
Preconditions.checkState( NSString.class.isAssignableFrom( value.getClass() ));
|
||||
|
||||
char character = key.charAt( 0 );
|
||||
char[] characterClass = ((NSString)value).getValue().toCharArray();
|
||||
characterClassesBuilder.put( character, new MPTemplateCharacterClass( character, characterClass ) );
|
||||
}
|
||||
ImmutableMap<Character, MPTemplateCharacterClass> characterClasses = characterClassesBuilder.build();
|
||||
|
||||
ImmutableMap.Builder<MPElementType, List<MPTemplate>> templatesBuilder = ImmutableMap.builder();
|
||||
for (final Map.Entry<String, NSObject> template : templatesDict.entrySet()) {
|
||||
String key = template.getKey();
|
||||
NSObject value = template.getValue();
|
||||
Preconditions.checkState( NSArray.class.isAssignableFrom( value.getClass() ) );
|
||||
|
||||
MPElementType type = MPElementType.forName( key );
|
||||
List<NSObject> templateStrings = ((NSArray) value).getValue();
|
||||
|
||||
ImmutableList.Builder<MPTemplate> typeTemplatesBuilder = ImmutableList.<MPTemplate>builder();
|
||||
for (final NSObject templateString : templateStrings)
|
||||
typeTemplatesBuilder.add( new MPTemplate( ((NSString) templateString).getValue(), characterClasses ) );
|
||||
|
||||
templatesBuilder.put( type, typeTemplatesBuilder.build() );
|
||||
}
|
||||
ImmutableMap<MPElementType, List<MPTemplate>> templates = templatesBuilder.build();
|
||||
|
||||
return new MPTemplates( templates );
|
||||
}
|
||||
catch (PropertyListException e) {
|
||||
logger.err( e, "Could not parse templates from: %s", templateResource );
|
||||
throw Throwables.propagate( e );
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.err( e, "Could not read templates from: %s", templateResource );
|
||||
throw Throwables.propagate( e );
|
||||
}
|
||||
finally {
|
||||
Closeables.closeQuietly( templateStream );
|
||||
}
|
||||
}
|
||||
|
||||
public MPTemplate getTemplateForTypeAtRollingIndex(final MPElementType type, final int templateIndex) {
|
||||
|
||||
List<MPTemplate> typeTemplates = templates.get( type );
|
||||
|
||||
return typeTemplates.get( templateIndex % typeTemplates.size() );
|
||||
}
|
||||
|
||||
public static void main(final String... arguments) {
|
||||
|
||||
loadFromPList( "templates.plist" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.primitives.Bytes;
|
||||
import com.lambdaworks.crypto.SCrypt;
|
||||
import com.lyndir.lhunath.opal.crypto.CryptUtils;
|
||||
import com.lyndir.lhunath.opal.system.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the Master Password algorithm.
|
||||
*
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public abstract class MasterPassword {
|
||||
|
||||
static final Logger logger = Logger.get( MasterPassword.class );
|
||||
private static final int MP_N = 32768;
|
||||
private static final int MP_r = 8;
|
||||
private static final int MP_p = 2;
|
||||
private static final int MP_dkLen = 64;
|
||||
private static final Charset MP_charset = Charsets.UTF_8;
|
||||
private static final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
private static final MessageDigests MP_hash = MessageDigests.SHA256;
|
||||
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
|
||||
private static final MPTemplates templates = MPTemplates.loadFromPList( "templates.plist" );
|
||||
|
||||
public static byte[] keyForPassword(final String password, final String username) {
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
byte[] nusernameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE )
|
||||
.order( MP_byteOrder )
|
||||
.putInt( username.length() )
|
||||
.array();
|
||||
byte[] salt = Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
|
||||
nusernameLengthBytes, //
|
||||
username.getBytes( MP_charset ) );
|
||||
|
||||
try {
|
||||
byte[] key = SCrypt.scrypt( password.getBytes( MP_charset ), salt, MP_N, MP_r, MP_p, MP_dkLen );
|
||||
logger.trc( "User: %s, password: %s derives to key ID: %s (took %.2fs)", username, password,
|
||||
CodeUtils.encodeHex( keyIDForKey( key ) ), (double) (System.currentTimeMillis() - start) / 1000 );
|
||||
|
||||
return key;
|
||||
}
|
||||
catch (GeneralSecurityException e) {
|
||||
throw logger.bug( e );
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] subkeyForKey(final byte[] key, final int subkeyLength) {
|
||||
|
||||
byte[] subkey = new byte[Math.min( subkeyLength, key.length )];
|
||||
System.arraycopy( key, 0, subkey, 0, subkey.length );
|
||||
|
||||
return subkey;
|
||||
}
|
||||
|
||||
public static byte[] keyIDForPassword(final String password, final String username) {
|
||||
|
||||
return keyIDForKey( keyForPassword( password, username ) );
|
||||
}
|
||||
|
||||
public static byte[] keyIDForKey(final byte[] key) {
|
||||
|
||||
return MP_hash.of( key );
|
||||
}
|
||||
|
||||
public static String generateContent(final MPElementType type, final String name, final byte[] key, int counter) {
|
||||
|
||||
Preconditions.checkArgument( type.getTypeClass() == MPElementTypeClass.Generated );
|
||||
Preconditions.checkArgument( !name.isEmpty() );
|
||||
Preconditions.checkArgument( key.length > 0 );
|
||||
|
||||
if (counter == 0)
|
||||
counter = (int) (System.currentTimeMillis() / (300 * 1000)) * 300;
|
||||
|
||||
byte[] nameLengthBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MP_byteOrder ).putInt( name.length() ).array();
|
||||
byte[] counterBytes = ByteBuffer.allocate( Integer.SIZE / Byte.SIZE ).order( MP_byteOrder ).putInt( counter ).array();
|
||||
logger.trc( "seed from: hmac-sha256(%s, 'com.lyndir.masterpassword' | %s | %s | %s)", CryptUtils.encodeBase64( key ),
|
||||
CodeUtils.encodeHex( nameLengthBytes ), name, CodeUtils.encodeHex( counterBytes ) );
|
||||
byte[] seed = MP_mac.of( key, Bytes.concat( "com.lyndir.masterpassword".getBytes( MP_charset ), //
|
||||
nameLengthBytes, //
|
||||
name.getBytes( MP_charset ), //
|
||||
counterBytes ) );
|
||||
logger.trc( "seed is: %s", CryptUtils.encodeBase64( seed ) );
|
||||
|
||||
Preconditions.checkState( seed.length > 0 );
|
||||
int templateIndex = seed[0] & 0xFF; // Mask the integer's sign.
|
||||
MPTemplate template = templates.getTemplateForTypeAtRollingIndex( type, templateIndex );
|
||||
logger.trc( "type: %s, template: %s", type, template );
|
||||
|
||||
StringBuilder password = new StringBuilder( template.length() );
|
||||
for (int i = 0; i < template.length(); ++i) {
|
||||
int characterIndex = seed[i + 1] & 0xFF; // Mask the integer's sign.
|
||||
MPTemplateCharacterClass characterClass = template.getCharacterClassAtIndex( i );
|
||||
char passwordCharacter = characterClass.getCharacterAtRollingIndex( characterIndex );
|
||||
logger.trc( "class: %s, index: %d, byte: 0x%02X, chosen password character: %s", characterClass, characterIndex, seed[i + 1],
|
||||
passwordCharacter );
|
||||
|
||||
password.append( passwordCharacter );
|
||||
}
|
||||
|
||||
return password.toString();
|
||||
}
|
||||
|
||||
public static void main(final String... arguments) {
|
||||
|
||||
String masterPassword = "test-mp";
|
||||
String username = "test-user";
|
||||
String siteName = "test-site";
|
||||
MPElementType siteType = MPElementType.GeneratedLong;
|
||||
int siteCounter = 42;
|
||||
|
||||
String sitePassword = generateContent( siteType, siteName, keyForPassword( masterPassword, username ), siteCounter );
|
||||
|
||||
logger.inf( "master password: %s, username: %s\nsite name: %s, site type: %s, site counter: %d\n => site password: %s",
|
||||
masterPassword, username, siteName, siteType, siteCounter, sitePassword );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lyndir.lhunath.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPElementEntity {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lyndir.lhunath.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPElementGeneratedEntity extends MPElementEntity {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.lyndir.lhunath.masterpassword.entity;
|
||||
|
||||
/**
|
||||
* <i>07 04, 2012</i>
|
||||
*
|
||||
* @author lhunath
|
||||
*/
|
||||
public class MPElementStoredEntity extends MPElementEntity {
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../Resources/ciphers.plist
|
||||
@@ -0,0 +1,78 @@
|
||||
<?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>MPElementGeneratedEntity</key>
|
||||
<dict>
|
||||
<key>Maximum Security Password</key>
|
||||
<array>
|
||||
<string>anoxxxxxxxxxxxxxxxxx</string>
|
||||
<string>axxxxxxxxxxxxxxxxxno</string>
|
||||
</array>
|
||||
<key>Long Password</key>
|
||||
<array>
|
||||
<string>CvcvnoCvcvCvcv</string>
|
||||
<string>CvcvCvcvnoCvcv</string>
|
||||
<string>CvcvCvcvCvcvno</string>
|
||||
<string>CvccnoCvcvCvcv</string>
|
||||
<string>CvccCvcvnoCvcv</string>
|
||||
<string>CvccCvcvCvcvno</string>
|
||||
<string>CvcvnoCvccCvcv</string>
|
||||
<string>CvcvCvccnoCvcv</string>
|
||||
<string>CvcvCvccCvcvno</string>
|
||||
<string>CvcvnoCvcvCvcc</string>
|
||||
<string>CvcvCvcvnoCvcc</string>
|
||||
<string>CvcvCvcvCvccno</string>
|
||||
<string>CvccnoCvccCvcv</string>
|
||||
<string>CvccCvccnoCvcv</string>
|
||||
<string>CvccCvccCvcvno</string>
|
||||
<string>CvcvnoCvccCvcc</string>
|
||||
<string>CvcvCvccnoCvcc</string>
|
||||
<string>CvcvCvccCvccno</string>
|
||||
<string>CvccnoCvcvCvcc</string>
|
||||
<string>CvccCvcvnoCvcc</string>
|
||||
<string>CvccCvcvCvccno</string>
|
||||
</array>
|
||||
<key>Medium Password</key>
|
||||
<array>
|
||||
<string>CvcnoCvc</string>
|
||||
<string>CvcCvcno</string>
|
||||
</array>
|
||||
<key>Short Password</key>
|
||||
<array>
|
||||
<string>Cvcn</string>
|
||||
</array>
|
||||
<key>Basic Password</key>
|
||||
<array>
|
||||
<string>aaanaaan</string>
|
||||
<string>aannaaan</string>
|
||||
<string>aaannaaa</string>
|
||||
</array>
|
||||
<key>PIN</key>
|
||||
<array>
|
||||
<string>nnnn</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>MPCharacterClasses</key>
|
||||
<dict>
|
||||
<key>V</key>
|
||||
<string>AEIOU</string>
|
||||
<key>C</key>
|
||||
<string>BCDFGHJKLMNPQRSTVWXYZ</string>
|
||||
<key>v</key>
|
||||
<string>aeiou</string>
|
||||
<key>c</key>
|
||||
<string>bcdfghjklmnpqrstvwxyz</string>
|
||||
<key>A</key>
|
||||
<string>AEIOUBCDFGHJKLMNPQRSTVWXYZ</string>
|
||||
<key>a</key>
|
||||
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz</string>
|
||||
<key>n</key>
|
||||
<string>0123456789</string>
|
||||
<key>o</key>
|
||||
<string>@&%?,=[]_:-+*$#!'^~;()/.</string>
|
||||
<key>x</key>
|
||||
<string>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,5 @@
|
||||
#Generated by Maven
|
||||
#Wed Jul 04 23:49:38 CEST 2012
|
||||
version=GIT-SNAPSHOT
|
||||
groupId=com.lyndir.lhunath.masterpassword
|
||||
artifactId=masterpassword-algorithm
|
||||
80
MasterPassword/Java/masterpassword-cli/pom.xml
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password CLI</name>
|
||||
<description>A CLI interface to the Master Password algorithm</description>
|
||||
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<artifactId>masterpassword-cli</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<!-- BUILD CONFIGURATION -->
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/scripts</directory>
|
||||
<filtering>true</filtering>
|
||||
<targetPath>${project.build.directory}</targetPath>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.lyndir.lhunath.masterpassword.CLI</mainClass>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<!-- DEPENDENCY MANAGEMENT -->
|
||||
<dependencies>
|
||||
|
||||
<!-- PROJECT REFERENCES -->
|
||||
<dependency>
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<artifactId>masterpassword-algorithm</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2008, Maarten Billemont
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.lyndir.lhunath.masterpassword;
|
||||
|
||||
import com.google.common.io.LineReader;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.lhunath.opal.system.util.ConversionUtils;
|
||||
import java.io.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* <p> <i>Jun 10, 2008</i> </p>
|
||||
*
|
||||
* @author mbillemo
|
||||
*/
|
||||
public class CLI {
|
||||
|
||||
static final Logger logger = Logger.get( CLI.class );
|
||||
|
||||
public static void main(final String[] args)
|
||||
throws IOException {
|
||||
|
||||
InputStream in = System.in;
|
||||
|
||||
/* Arguments. */
|
||||
String userName = null, siteName = null;
|
||||
int counter = 1;
|
||||
MPElementType type = MPElementType.GeneratedLong;
|
||||
boolean typeArg = false, counterArg = false, userNameArg = false;
|
||||
for (final String arg : Arrays.asList( args ))
|
||||
if ("-t".equals( arg ) || "--type".equals( arg ))
|
||||
typeArg = true;
|
||||
else if (typeArg) {
|
||||
if ("list".equalsIgnoreCase( arg )) {
|
||||
System.out.format( "%30s | %s\n", "type", "description" );
|
||||
for (final MPElementType aType : MPElementType.values())
|
||||
System.out.format( "%30s | %s\n", aType.getName(), aType.getDescription() );
|
||||
System.exit( 0 );
|
||||
}
|
||||
|
||||
type = MPElementType.forName( arg );
|
||||
typeArg = false;
|
||||
} else if ("-c".equals( arg ) || "--counter".equals( arg ))
|
||||
counterArg = true;
|
||||
else if (counterArg) {
|
||||
counter = ConversionUtils.toIntegerNN( arg );
|
||||
counterArg = false;
|
||||
} else if ("-u".equals( arg ) || "--username".equals( arg ))
|
||||
userNameArg = true;
|
||||
else if (userNameArg) {
|
||||
userName = arg;
|
||||
userNameArg = false;
|
||||
} else if ("-h".equals( arg ) || "--help".equals( arg )) {
|
||||
System.out.println();
|
||||
System.out.println( "\tMaster Password CLI" );
|
||||
System.out.println( "\t\tLyndir" );
|
||||
|
||||
System.out.println( "[options] [site name]" );
|
||||
System.out.println();
|
||||
System.out.println( "Available options:" );
|
||||
System.out.println( "\t-t | --type [site password type]" );
|
||||
System.out.format( "\t\tDefault: %s. The password type to use for this site.\n", type.getName() );
|
||||
System.out.println( "\t\tUse 'list' to see the available types." );
|
||||
|
||||
System.out.println();
|
||||
System.out.println( "\t-c | --counter [site counter]" );
|
||||
System.out.format( "\t\tDefault: %d. The counter to use for this site.\n", counter );
|
||||
System.out.println( "\t\tIncrement the counter if you need a new password." );
|
||||
|
||||
System.out.println();
|
||||
System.out.println( "\t-u | --username [user's name]" );
|
||||
System.out.println( "\t\tDefault: asked. The name of the current user." );
|
||||
|
||||
System.out.println();
|
||||
return;
|
||||
} else
|
||||
siteName = arg;
|
||||
LineReader lineReader = new LineReader( new InputStreamReader( System.in ) );
|
||||
if (siteName == null) {
|
||||
System.out.print( "Site name: " );
|
||||
siteName = lineReader.readLine();
|
||||
}
|
||||
if (userName == null) {
|
||||
System.out.print( "User's name: " );
|
||||
userName = lineReader.readLine();
|
||||
}
|
||||
System.out.print( "User's master password: " );
|
||||
String masterPassword = lineReader.readLine();
|
||||
|
||||
String sitePassword = MasterPassword.generateContent( type, siteName, MasterPassword.keyForPassword( masterPassword, userName ),
|
||||
counter );
|
||||
System.out.println( sitePassword );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<configuration scan="true">
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>%-8relative %22c{0} [%-5level] %msg%n</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<logger name="com.lyndir" level="TRACE" />
|
||||
|
||||
<!--
|
||||
<logger name="org.apache.wicket" level="DEBUG" />
|
||||
-->
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
4
MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd "${BASH_SOURCE[0]%/*}"
|
||||
java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"
|
||||
BIN
MasterPassword/Java/masterpassword-cli/target/lib/asm-3.3.1.jar
Normal file
BIN
MasterPassword/Java/masterpassword-cli/target/lib/guava-r09.jar
Normal file
@@ -0,0 +1,5 @@
|
||||
#Generated by Maven
|
||||
#Wed Jul 04 23:49:39 CEST 2012
|
||||
version=GIT-SNAPSHOT
|
||||
groupId=com.lyndir.lhunath.masterpassword
|
||||
artifactId=masterpassword-cli
|
||||
4
MasterPassword/Java/masterpassword-cli/target/mpw
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd "${BASH_SOURCE[0]%/*}"
|
||||
java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"
|
||||
26
MasterPassword/Java/pom.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- PROJECT METADATA -->
|
||||
<parent>
|
||||
<groupId>com.lyndir.lhunath</groupId>
|
||||
<artifactId>lyndir</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<name>Master Password</name>
|
||||
<description>A Java implementation of the Master Password algorithm.</description>
|
||||
|
||||
<groupId>com.lyndir.lhunath.masterpassword</groupId>
|
||||
<artifactId>masterpassword</artifactId>
|
||||
<version>GIT-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>masterpassword-algorithm</module>
|
||||
<module>masterpassword-cli</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
@@ -11,7 +11,7 @@
|
||||
@interface MPAppDelegate_Shared (Key)
|
||||
|
||||
- (BOOL)signInAsUser:(MPUserEntity *)user usingMasterPassword:(NSString *)password;
|
||||
- (void)signOut;
|
||||
- (void)signOutAnimated:(BOOL)animated;
|
||||
|
||||
- (void)storeSavedKeyFor:(MPUserEntity *)user;
|
||||
- (void)forgetSavedKeyFor:(MPUserEntity *)user;
|
||||
|
||||
@@ -73,14 +73,15 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)signOut {
|
||||
- (void)signOutAnimated:(BOOL)animated {
|
||||
|
||||
if (self.key)
|
||||
self.key = nil;
|
||||
|
||||
if (self.activeUser) {
|
||||
self.activeUser = nil;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationSignedOut object:self];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationSignedOut object:self userInfo:
|
||||
[NSDictionary dictionaryWithObject:PearlBool(animated) forKey:@"animated"]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
#import "MPEntities.h"
|
||||
|
||||
|
||||
#define MP_N 131072
|
||||
#define MP_N 32768
|
||||
#define MP_r 8
|
||||
#define MP_p 1
|
||||
#define MP_p 2
|
||||
#define MP_dkLen 64
|
||||
#define MP_hash PearlHashSHA256
|
||||
|
||||
@@ -27,7 +27,7 @@ NSData *keyForPassword(NSString *password, NSString *username) {
|
||||
[username dataUsingEncoding:NSUTF8StringEncoding],
|
||||
nil] N:MP_N r:MP_r p:MP_p];
|
||||
|
||||
trc(@"User: %@, password: %@ derives to key ID: %@ (took %0.2f)", username, password, [keyIDForKey(key) encodeHex], -[start timeIntervalSinceNow]);
|
||||
trc(@"User: %@, password: %@ derives to key ID: %@ (took %0.2fs)", username, password, [keyIDForKey(key) encodeHex], -[start timeIntervalSinceNow]);
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -184,16 +184,18 @@ NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *key, ui
|
||||
withExtension:@"plist"]];
|
||||
|
||||
// Determine the seed whose bytes will be used for calculating a password
|
||||
trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %u | %@ | %u)", key, name.length, name, counter);
|
||||
uint32_t ncounter = htonl(counter), nnameLength = htonl(name.length);
|
||||
NSData *counterBytes = [NSData dataWithBytes:&ncounter length:sizeof(ncounter)];
|
||||
NSData *nameLengthBytes = [NSData dataWithBytes:&nnameLength length:sizeof(nnameLength)];
|
||||
trc(@"seed from: hmac-sha256(%@, 'com.lyndir.masterpassword' | %@ | %@ | %@)", [key encodeBase64], [nameLengthBytes encodeHex], name, [counterBytes encodeHex]);
|
||||
NSData *seed = [[NSData dataByConcatenatingDatas:
|
||||
[@"com.lyndir.masterpassword" dataUsingEncoding:NSUTF8StringEncoding],
|
||||
[NSData dataWithBytes:&nnameLength length:sizeof(nnameLength)],
|
||||
nameLengthBytes,
|
||||
[name dataUsingEncoding:NSUTF8StringEncoding],
|
||||
[NSData dataWithBytes:&ncounter length:sizeof(ncounter)],
|
||||
counterBytes,
|
||||
nil]
|
||||
hmacWith:PearlHashSHA256 key:key];
|
||||
trc(@"seed is: %@", seed);
|
||||
trc(@"seed is: %@", [seed encodeBase64]);
|
||||
const char *seedBytes = seed.bytes;
|
||||
|
||||
// Determine the cipher from the first seed byte.
|
||||
@@ -213,7 +215,7 @@ NSString *MPCalculateContent(MPElementType type, NSString *name, NSData *key, ui
|
||||
NSString *character = [cipherClassCharacters substringWithRange:NSMakeRange(keyByte % [cipherClassCharacters length],
|
||||
1)];
|
||||
|
||||
trc(@"class %@ has characters: %@, selected: %@", cipherClass, cipherClassCharacters, character);
|
||||
trc(@"class %@ has characters: %@, index: %u, selected: %@", cipherClass, cipherClassCharacters, keyByte, character);
|
||||
[content appendString:character];
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,11 @@
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:MPNotificationSignedOut object:nil queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
[self.navigationController performSegueWithIdentifier:@"MP_Unlock" sender:nil];
|
||||
if ([[note.userInfo objectForKey:@"animated"] boolValue])
|
||||
[self.navigationController performSegueWithIdentifier:@"MP_Unlock" sender:nil];
|
||||
else
|
||||
[self.navigationController presentViewController:[self.navigationController.storyboard instantiateViewControllerWithIdentifier:@"MPUnlockViewController"]
|
||||
animated:NO completion:nil];
|
||||
}];
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil
|
||||
usingBlock:^(NSNotification *note) {
|
||||
@@ -325,7 +329,7 @@
|
||||
[self saveContext];
|
||||
|
||||
if (![[MPiOSConfig get].rememberLogin boolValue])
|
||||
[self signOut];
|
||||
[self signOutAnimated:NO];
|
||||
|
||||
[TestFlight passCheckpoint:MPCheckpointDeactivated];
|
||||
}
|
||||
@@ -487,7 +491,7 @@
|
||||
inf(@"Unsetting master password for: %@.", user.userID);
|
||||
user.keyID = nil;
|
||||
[self forgetSavedKeyFor:user];
|
||||
[self signOut];
|
||||
[self signOutAnimated:YES];
|
||||
|
||||
[TestFlight passCheckpoint:MPCheckpointChangeMP];
|
||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointChangeMP
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPSearchResultsDelegate, UIWebViewDelegate, MFMailComposeViewControllerDelegate>
|
||||
|
||||
@property (strong, nonatomic) MPElementEntity *activeElement;
|
||||
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchResultsController;
|
||||
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate;
|
||||
@property (strong, nonatomic) IBOutlet UILongPressGestureRecognizer *resetPasswordCounterGesture;
|
||||
@property (weak, nonatomic) IBOutlet UITextField *contentField;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *typeButton;
|
||||
@property (weak, nonatomic) IBOutlet UIWebView *helpView;
|
||||
@@ -33,7 +34,6 @@
|
||||
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
|
||||
@property (weak, nonatomic) IBOutlet UIView *actionsTipContainer;
|
||||
@property (weak, nonatomic) IBOutlet UIView *typeTipContainer;
|
||||
@property (strong, nonatomic) IBOutlet UILongPressGestureRecognizer *resetPasswordCounterGesture;
|
||||
|
||||
@property (copy) void (^contentTipCleanup)(BOOL finished);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
@implementation MPMainViewController
|
||||
@synthesize activeElement = _activeElement;
|
||||
@synthesize searchResultsController = _searchResultsController;
|
||||
@synthesize searchDelegate = _searchDelegate;
|
||||
@synthesize typeButton = _typeButton;
|
||||
@synthesize helpView = _helpView;
|
||||
@synthesize siteName = _siteName;
|
||||
@@ -67,6 +67,15 @@
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
|
||||
self.searchDelegate = [MPSearchDelegate new];
|
||||
self.searchDelegate.delegate = self;
|
||||
self.searchDelegate.searchDisplayController = self.searchDisplayController;
|
||||
self.searchDelegate.searchTipContainer = self.searchTipContainer;
|
||||
self.searchDisplayController.searchBar.delegate = self.searchDelegate;
|
||||
self.searchDisplayController.delegate = self.searchDelegate;
|
||||
self.searchDisplayController.searchResultsDelegate = self.searchDelegate;
|
||||
self.searchDisplayController.searchResultsDataSource = self.searchDelegate;
|
||||
|
||||
self.resetPasswordCounterGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(resetPasswordCounter:)];
|
||||
[self.passwordIncrementer addGestureRecognizer:self.resetPasswordCounterGesture];
|
||||
@@ -136,7 +145,6 @@
|
||||
|
||||
[self setContentField:nil];
|
||||
[self setTypeButton:nil];
|
||||
[self setSearchResultsController:nil];
|
||||
[self setHelpView:nil];
|
||||
[self setSiteName:nil];
|
||||
[self setPasswordCounter:nil];
|
||||
@@ -153,6 +161,7 @@
|
||||
[self setSearchTipContainer:nil];
|
||||
[self setActionsTipContainer:nil];
|
||||
[self setTypeTipContainer:nil];
|
||||
[self setSearchDelegate:nil];
|
||||
[self setResetPasswordCounterGesture:nil];
|
||||
[super viewDidUnload];
|
||||
}
|
||||
@@ -503,7 +512,7 @@
|
||||
#endif
|
||||
{
|
||||
inf(@"Action: Sign out");
|
||||
[[MPAppDelegate get] signOut];
|
||||
[[MPAppDelegate get] signOutAnimated:YES];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@
|
||||
|
||||
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
|
||||
|
||||
dbg(@"Search ended with: %@", controller.searchBar.text);
|
||||
controller.searchBar.prompt = nil;
|
||||
controller.searchBar.searchResultsButtonSelected = NO;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,12 @@
|
||||
|
||||
assert(self.navigationController.topViewController == self);
|
||||
|
||||
[delegate didSelectType:[self typeAtIndexPath:indexPath]];
|
||||
MPElementType type = [self typeAtIndexPath:indexPath];
|
||||
if (type == NSNotFound)
|
||||
// Selected a non-type row.
|
||||
return;
|
||||
|
||||
[delegate didSelectType:type];
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
|
||||
@@ -416,20 +416,10 @@ Your passwords will be AES-encrypted with your master password.</string>
|
||||
<scene sceneID="U26-Zf-euQ">
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="mK2-p1-3zC" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<customObject id="0QO-2P-OhD" customClass="MPSearchDelegate">
|
||||
<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="MPMainViewController" sceneMemberID="viewController">
|
||||
@@ -621,9 +611,6 @@ L4m3P4sSw0rD</string>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
<gestureRecognizers/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" keyboardType="URL"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="0QO-2P-OhD" id="Maj-Iz-6Hb"/>
|
||||
</connections>
|
||||
</searchBar>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" id="zOR-Du-qRL">
|
||||
<rect key="frame" x="10" y="15" width="300" height="60"/>
|
||||
@@ -734,7 +721,6 @@ L4m3P4sSw0rD</string>
|
||||
<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"/>
|
||||
@@ -1379,6 +1365,7 @@ L4m3P4sSw0rD</string>
|
||||
<relationship kind="outlet" name="passwordEdit" candidateClass="UIButton"/>
|
||||
<relationship kind="outlet" name="passwordIncrementer" candidateClass="UIButton"/>
|
||||
<relationship kind="outlet" name="resetPasswordCounterGesture" candidateClass="UILongPressGestureRecognizer"/>
|
||||
<relationship kind="outlet" name="searchDelegate" candidateClass="MPSearchDelegate"/>
|
||||
<relationship kind="outlet" name="searchResultsController" candidateClass="MPSearchDelegate"/>
|
||||
<relationship kind="outlet" name="searchTipContainer" candidateClass="UIView"/>
|
||||
<relationship kind="outlet" name="siteName" candidateClass="UILabel"/>
|
||||
|
||||
BIN
Resources/AppStore-iOS.png
Normal file
|
After Width: | Height: | Size: 571 KiB |
|
Before Width: | Height: | Size: 109 KiB After Width: | Height: | Size: 545 KiB |
BIN
Resources/iTunesArtwork-Square.png
Normal file
|
After Width: | Height: | Size: 563 KiB |
1
Site/MasterPassword_PressKit.zip
Symbolic link
@@ -0,0 +1 @@
|
||||
../Press/./MasterPassword_PressKit.zip
|
||||
@@ -85,10 +85,10 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984"><img src="img/appstore.png" /></a>
|
||||
<header>
|
||||
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984"><img src="img/appstore.png" /></a>
|
||||
<h1><a href="index.html"><img class="logo" src="img/iTunesArtwork-Bare.png" /> Master Password</a></h1>
|
||||
<div class="divider"></div>
|
||||
|
||||
@@ -118,13 +118,13 @@
|
||||
<p>
|
||||
Master Password uses a stateless algorithm that relies solely on its implementation and the user's inputs. The user is expected to remember the following information:
|
||||
<ul>
|
||||
<li><b>The master password</b> (eg. <em>pink fluffy door frame</em>):<br />
|
||||
<li><strong>The master password</strong> (eg. <em>pink fluffy door frame</em>):<br />
|
||||
This is a secret that the user shares with nobody.</li>
|
||||
<li><b>The site name</b> (eg. <em>apple.com</em>):<br />
|
||||
<li><strong>The site name</strong> (eg. <em>apple.com</em>):<br />
|
||||
The user chooses a name for each site. Its domain name is an ideal choice, since it needn't necessarily be remembered.</li>
|
||||
<li><b>The site's password counter</b> (default: <em>0</em>):<br />
|
||||
<li><strong>The site's password counter</strong> (default: <em>0</em>):<br />
|
||||
This is an integer that can be incremented when the user needs a new password for the site.</li>
|
||||
<li><b>The site's password type</b> (default: <em>Long Password</em>):<br />
|
||||
<li><strong>The site's password type</strong> (default: <em>Long Password</em>):<br />
|
||||
This type determines the format of the output password. It can be changed if the site's password policy does not accept passwords of this format.</li>
|
||||
</ul>
|
||||
</p>
|
||||
@@ -132,26 +132,33 @@
|
||||
In short, the algorithm is comprised of the following steps:
|
||||
<ul>
|
||||
<li>Determining the master <code>key</code></li>
|
||||
<li>Determining the cipher <code>seed</code></li>
|
||||
<li>Determining the template <code>seed</code></li>
|
||||
<li>Encoding a user-friendly <code>password</code></li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>
|
||||
A note on types:
|
||||
<ul>
|
||||
<li>Any character string is UTF-8 de- or encoded, depending on context.</li>
|
||||
<li>Any number is converted to 32-bit network byte order.</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h2>The Master Password</h2>
|
||||
<p>
|
||||
The user chooses a single master password, preferably sufficiently long to harden against brute-force attacks. Master Password recommends absurd two or three-word sentences as they're easily remembered and generally sufficiently high in entropy.
|
||||
The user chooses a single master password, preferably sufficiently long to harden against brute-force attacks. Master Password recommends absurd three or four-word sentences as they're easily remembered and generally sufficiently high in entropy.
|
||||
</p>
|
||||
<p>
|
||||
The application then creates a <a href="http://www.tarsnap.com/scrypt.html" onclick="_gaq.push(['_trackPageview', '/outbound/tarsnap.com/scrypt.html">scrypt</a> key derivative from the user's password. This process takes quite a bit of processing time and memory. This step exists to make brute-force attempts at guessing the master password from a given output password <b>far more difficult</b>, to practically infeasible, even for otherwise vulnerable password strings.
|
||||
The application then creates a <a href="http://www.tarsnap.com/scrypt.html" onclick="_gaq.push(['_trackPageview', '/outbound/tarsnap.com/scrypt.html">scrypt</a> key derivative from the user's password. This process takes quite a bit of processing time and memory. This step exists to make brute-force attempts at guessing the master password from a given output password <strong>far more difficult</strong>, to practically infeasible, even for otherwise vulnerable password strings.
|
||||
</p>
|
||||
<code><pre>
|
||||
key = scrypt( P, S, N, r, p, dkLen )
|
||||
where
|
||||
P = master password (UTF-8)
|
||||
S = <empty>
|
||||
N = 16384
|
||||
P = master password
|
||||
S = "com.lyndir.masterpassword" . name length . name
|
||||
N = 32768
|
||||
r = 8
|
||||
p = 1
|
||||
p = 2
|
||||
dkLen = 64
|
||||
</pre></code>
|
||||
|
||||
@@ -167,8 +174,7 @@
|
||||
These input values are combined in a byte array, separated by a single <code>NUL</code> byte. In order, the input values are the <code>site name</code> (UTF-8 decoded), the master <code>key</code>, and a <code>salt</code> (this is the password counter, a 32-bit unsigned integer in network byte order). The byte array is hashed using the SHA-1 algorithm to yield the <code>seed</code> as a result.
|
||||
</p>
|
||||
<code><pre>
|
||||
salt = htonl( password counter )
|
||||
seed = sha1( site name . "\0" . key . "\0" . salt )
|
||||
seed = hmac-sha256( key, "com.lyndir.masterpassword" . site name length . site name . counter )
|
||||
</pre></code>
|
||||
|
||||
<h2>Generating The Output</h2>
|
||||
@@ -180,33 +186,58 @@
|
||||
</p>
|
||||
<p>
|
||||
Since the idea is that the output password can be used directly as a password to protect the user's account on the site, it needs to be able to pass the site's password policy.
|
||||
Master Password addresses this problem by introducing <em>password types</em>. Each password type describes what an output password must look like and maps to a set of <code>ciphers</code>. Ciphers describe the resulting output password using a series of characters that map to character groups of candidate output characters. A cipher has the same length as the output password it yields. Each character in the cipher maps to a specific character group. At each position of the output password, a character is chosen from the character group identified by the character in the cipher at the same position.
|
||||
Master Password addresses this problem by introducing <em>password types</em>. Each password type describes what an output password must look like and maps to a set of <code>templates</code>. Templates describe the resulting output password using a series of characters that map to character groups of candidate output characters. A template has the same length as the output password it yields. Each character in the template maps to a specific character group. At each position of the output password, a character is chosen from the character group identified by the character in the template at the same position.
|
||||
</p>
|
||||
<p>
|
||||
The following ciphers are defined:
|
||||
The following templates are defined:
|
||||
<ul>
|
||||
<li>Type: <b>Long Password</b></li>
|
||||
<li>Type: <strong>Maximum Security Password</strong></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>CvcvCvcvnoCvcv</code></li>
|
||||
<li><code>CvcvnoCvcvCvcv</code></li>
|
||||
<li><code>CvcvCvcvCvcvno</code></li>
|
||||
<li><code>anoxxxxxxxxxxxxxxxxx</li></code>
|
||||
<li><code>axxxxxxxxxxxxxxxxxno</li></code>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Type: <b>Medium Password</b></li>
|
||||
<li>Type: <strong>Long Password</strong></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>CvcvnoCvcvCvcv</li></code>
|
||||
<li><code>CvcvCvcvnoCvcv</li></code>
|
||||
<li><code>CvcvCvcvCvcvno</li></code>
|
||||
<li><code>CvccnoCvcvCvcv</li></code>
|
||||
<li><code>CvccCvcvnoCvcv</li></code>
|
||||
<li><code>CvccCvcvCvcvno</li></code>
|
||||
<li><code>CvcvnoCvccCvcv</li></code>
|
||||
<li><code>CvcvCvccnoCvcv</li></code>
|
||||
<li><code>CvcvCvccCvcvno</li></code>
|
||||
<li><code>CvcvnoCvcvCvcc</li></code>
|
||||
<li><code>CvcvCvcvnoCvcc</li></code>
|
||||
<li><code>CvcvCvcvCvccno</li></code>
|
||||
<li><code>CvccnoCvccCvcv</li></code>
|
||||
<li><code>CvccCvccnoCvcv</li></code>
|
||||
<li><code>CvccCvccCvcvno</li></code>
|
||||
<li><code>CvcvnoCvccCvcc</li></code>
|
||||
<li><code>CvcvCvccnoCvcc</li></code>
|
||||
<li><code>CvcvCvccCvccno</li></code>
|
||||
<li><code>CvccnoCvcvCvcc</li></code>
|
||||
<li><code>CvccCvcvnoCvcc</li></code>
|
||||
<li><code>CvccCvcvCvccno</li></code>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Type: <strong>Medium Password</strong></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>CvcnoCvc</code></li>
|
||||
<li><code>CvcCvcno</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Type: <b>Short Password</b></li>
|
||||
<li>Type: <strong>Short Password</strong></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>Cvcn</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Type: <b>Basic Password</b></li>
|
||||
<li>Type: <strong>Basic Password</strong></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>aaanaaan</code></li>
|
||||
@@ -214,7 +245,7 @@
|
||||
<li><code>aaannaaa</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Type: <b>PIN</b></li>
|
||||
<li>Type: <strong>PIN</strong></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>nnnn</code></li>
|
||||
@@ -226,70 +257,70 @@
|
||||
By default, Master Password uses the <em>Long Password</em> type for any new passwords. The user is able to choose a different password type, which is normally only done if the site's password policy is incompatible with the output password produced by this type.
|
||||
</p>
|
||||
<p>
|
||||
To create the create the output password, the bytes in the <code>seed</code> are encoded according to the cipher. The first <code>seed</code> byte is used to determine which of the type's ciphers to use for encoding an output password. We take the byte value of the first <code>seed</code> byte modulo the amount of ciphers set for the chosen password type and use the result as a zero-based index in the cipher list for the password type.
|
||||
To create the create the output password, the bytes in the <code>seed</code> are encoded according to the template. The first <code>seed</code> byte is used to determine which of the type's templates to use for encoding an output password. We take the byte value of the first <code>seed</code> byte modulo the amount of templates set for the chosen password type and use the result as a zero-based index in the template list for the password type.
|
||||
</p>
|
||||
<code><pre>
|
||||
ciphers = [ "CvcvCvcvnoCvcv", "CvcvnoCvcvCvcv", "CvcvCvcvCvcvno" ]
|
||||
cipher = ciphers[ seed[0] % count( ciphers ) ]
|
||||
templates = [ "CvcvCvcvnoCvcv", "CvcvnoCvcvCvcv", "CvcvCvcvCvcvno", ... ]
|
||||
template = templates[ seed[0] % count( templates ) ]
|
||||
</pre></code>
|
||||
<p>
|
||||
Now that we know what cipher to use for building our output password, all that's left is to iterate the cipher, and produce a character of password output for each step. When we iterate the cipher (index <code>i</code>), we look in the character group identified by the character (string <code>passChars</code>) in the cipher at index <code>i</code>.
|
||||
Now that we know what template to use for building our output password, all that's left is to iterate the template, and produce a character of password output for each step. When we iterate the template (index <code>i</code>), we look in the character group identified by the character (string <code>passChars</code>) in the template at index <code>i</code>.
|
||||
</p>
|
||||
<p>
|
||||
The following character groups (<code>passChars</code>) are defined:
|
||||
<ul>
|
||||
<li>Cipher character: <code>V</code></li>
|
||||
<li>Template character: <code>V</code></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>AEIOU</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>C</code></li>
|
||||
<li>Template character: <code>C</code></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>BCDFGHJKLMNPQRSTVWXYZ</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>v</code></li>
|
||||
<li>Template character: <code>v</code></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>aeiou</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>c</code></li>
|
||||
<li>Template character: <code>c</code></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>bcdfghjklmnpqrstvwxyz</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>A</code> (<code>= V . C</code>)</li>
|
||||
<li>Template character: <code>A</code> (<code>= V . C</code>)</li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>AEIOUBCDFGHJKLMNPQRSTVWXYZ</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>a</code> (<code>= V . v . C . c</code>)</li>
|
||||
<li>Template character: <code>a</code> (<code>= V . v . C . c</code>)</li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>n</code></li>
|
||||
<li>Template character: <code>n</code></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>0123456789</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>o</code></li>
|
||||
<li>Template character: <code>o</code></li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>!@#$%^&*()</code></li>
|
||||
<li><code>@&%?,=[]_:-+*$#!'^~;()/.</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cipher character: <code>X</code> (<code>= a . n . o</code>)</li>
|
||||
<li>Template character: <code>X</code> (<code>= a . n . o</code>)</li>
|
||||
<li>
|
||||
<ul>
|
||||
<li><code>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()</code></li>
|
||||
<li><code>AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789@&%?,=[]_:-+*$#!'^~;()/.</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -21,7 +21,7 @@ h1 {
|
||||
font-weight: 100;
|
||||
}
|
||||
strong {
|
||||
font-weight: 400;
|
||||
font-weight: 600;
|
||||
}
|
||||
h1 .sub {
|
||||
font-size: 0.5em;
|
||||
@@ -148,7 +148,7 @@ header .divider {
|
||||
header a, header .link, header :link,
|
||||
#fixedheader a, #fixedheader .link, #fixedheader :link {
|
||||
font-family: Exo;
|
||||
font-weight: 700;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
header a:hover, header .link:hover,
|
||||
@@ -258,6 +258,48 @@ header .appstore {
|
||||
/* appstore.png */
|
||||
bottom: -25px;
|
||||
}
|
||||
.tip {
|
||||
background: url("../img/tip.png") no-repeat;
|
||||
color: white;
|
||||
|
||||
position: absolute;
|
||||
display: block;
|
||||
right: 0;
|
||||
width: 410px;
|
||||
height: 60px;
|
||||
padding: 12px 20px;
|
||||
margin-top: -60px;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
font: 14px "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", "Liberation Sans", sans-serif;
|
||||
}
|
||||
.footnote {
|
||||
color: #444;
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 2px;
|
||||
|
||||
font: 14px "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", "Liberation Sans", sans-serif !important;
|
||||
}
|
||||
.footnote:hover {
|
||||
color: #666;
|
||||
}
|
||||
*>.nothover {
|
||||
display: inline-block;
|
||||
}
|
||||
*:hover>.nothover {
|
||||
display: none;
|
||||
}
|
||||
*>.hover {
|
||||
display: none;
|
||||
}
|
||||
*:hover>.hover {
|
||||
display: inline-block;
|
||||
}
|
||||
.columns {
|
||||
position: relative;
|
||||
clear: both;
|
||||
|
||||
BIN
Site/img/iTunesArtwork-Rounded.png
Normal file
|
After Width: | Height: | Size: 529 KiB |
BIN
Site/img/iTunesArtwork.png
Normal file
|
After Width: | Height: | Size: 510 KiB |
BIN
Site/img/screenshot.png
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
Site/img/tip.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
@@ -9,25 +9,11 @@
|
||||
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
|
||||
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
|
||||
|
||||
<link rel='stylesheet' type='text/css' href='http://fonts.googleapis.com/css?family=Exo:100,400,600,900,100italic,400italic,600italic' />
|
||||
<link rel="stylesheet" type="text/css" href="http://fonts.googleapis.com/css?family=Exo:100,400,600,900,100italic,400italic,600italic" />
|
||||
<link rel="stylesheet" type="text/css" href="css/ml-shadows.css" />
|
||||
<link rel="stylesheet" type="text/css" href="css/screen.css" />
|
||||
|
||||
<script src="js/jquery-1.6.1.min.js" type="text/javascript"></script>
|
||||
<script src="js/functions.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$(window).scroll(function() {
|
||||
if ($(window).scrollTop() > 100) {
|
||||
$(".appstore").show();
|
||||
$("header .appstore").hide();
|
||||
} else {
|
||||
$(".appstore").hide();
|
||||
$("header .appstore").show();
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
<!-- Google Analytics -->
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-90535-15']);
|
||||
@@ -78,13 +64,43 @@
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(_ue, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
|
||||
|
||||
<!-- Nivo Slider -->
|
||||
<link rel="stylesheet" href="js/nivo-slider/nivo-slider.css" type="text/css" media="screen" />
|
||||
<script src="js/nivo-slider/jquery.nivo.slider.pack.js" type="text/javascript"></script>
|
||||
|
||||
<!-- Page JS -->
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$(window).scroll(function() {
|
||||
if ($(window).scrollTop() > 100) {
|
||||
$(".appstore").show();
|
||||
$("header .appstore").hide();
|
||||
} else {
|
||||
$(".appstore").hide();
|
||||
$("header .appstore").show();
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body id="frontpage">
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984"><img src="img/appstore.png" /></a>
|
||||
<header>
|
||||
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984">
|
||||
<span class="tip">
|
||||
<span class="nothover">Tell us what you thought and get a free copy for a friend!</span>
|
||||
<span class="hover">The most constructive feedback earns a promo code.</span>
|
||||
</span>
|
||||
<img src="img/appstore.png" />
|
||||
</a>
|
||||
<h1><a href="index.html"><img class="logo" src="img/iTunesArtwork-Bare.png" /> Master Password</a></h1>
|
||||
<a class="footnote" href="mailto:masterpassword@lyndir.com">masterpassword@lyndir.com</a>
|
||||
<div class="divider"></div>
|
||||
|
||||
</header>
|
||||
@@ -93,6 +109,23 @@
|
||||
</div>
|
||||
<!--a href="http://bit.ly/vNN5Zi" onclick="_gaq.push(['_trackPageview', '/outbound/testflight']);" id="ribbon"></a-->
|
||||
|
||||
<!--section class="heading">
|
||||
<div>
|
||||
|
||||
<div class="slider-wrapper">
|
||||
<div id="slider" class="nivoSlider">
|
||||
<img src="images/slide1.jpg" alt="" />
|
||||
<a href="http://dev7studios.com"><img src="images/slide2.jpg" alt="" title="#htmlcaption" /></a>
|
||||
<img src="images/slide3.jpg" alt="" title="This is an example of a caption" />
|
||||
<img src="images/slide4.jpg" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="htmlcaption" class="nivo-html-caption">
|
||||
<strong>This</strong> is an example of a <em>HTML</em> caption with <a href="#">a link</a>.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section-->
|
||||
<section class="heading">
|
||||
<div>
|
||||
<div class="sidebox">
|
||||
@@ -112,7 +145,7 @@
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p><b>Master Password is a <em>stateless solution</em></b>, which means <strong>your passwords aren't saved <em>anywhere</em></strong>. Not in your head, not in a notebook, not on your computer and not in the cloud.<br />
|
||||
<p><strong>Master Password is a <em>stateless solution</em></strong>, which means <strong>your passwords aren't saved <em>anywhere</em></strong>. Not in your head, not in a notebook, not on your computer and not in the cloud.<br />
|
||||
Nothing to store means nothing to keep safe and nothing to lose.</p>
|
||||
|
||||
<p>Master Password just recreates the passwords for your sites whenever you need them: instantly and on-demand. At the same time it makes sure that your accounts are adequately protected with <em>secure and unique</em> passwords.</p>
|
||||
@@ -120,11 +153,11 @@
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>Master Password is <b>different</b> from other vault-like password solutions. It helps you set <b>secure passwords</b> for your sites, and at the same time makes <b>losing your passwords almost impossible</b>.</p>
|
||||
<p>Master Password is <strong>different</strong> from other vault-like password solutions. It helps you set <strong>secure passwords</strong> for your sites, and at the same time makes <strong>losing your passwords almost impossible</strong>.</p>
|
||||
|
||||
<p>Built on algorithms such as <a href="http://www.bsdcan.org/2009/schedule/events/147.en.html">scrypt</a> and <a href="http://en.wikipedia.org/wiki/HMAC">HMAC-SHA256</a>, your master password is kept safe even if websites you use get hacked.</p>
|
||||
|
||||
<p>As to prove a point, <a href="http://www.washingtonpost.com/business/technology/linkedin-eharmony-deal-with-breach-aftermath/2012/06/07/gJQAwqs5KV_story.html"><b>LinkedIn</b>, <b>eHarmony</b></a>, and <a href="http://securitywatch.pcmag.com/none/298865-last-fm-joins-eharmony-linkedin-to-celebrate-breach-week"><b>Last.FM</b></a> have announced breaches that compromise millions of passwords in the past month alone. These breaches have leaked "<em>hashes</em>" of people's passwords, which make it trivial for attackers to find out the actual passwords <em>if they're not secure enough</em>.</p>
|
||||
<p>As to prove a point, <a href="http://www.washingtonpost.com/business/technology/linkedin-eharmony-deal-with-breach-aftermath/2012/06/07/gJQAwqs5KV_story.html"><strong>LinkedIn</strong>, <strong>eHarmony</strong></a>, and <a href="http://securitywatch.pcmag.com/none/298865-last-fm-joins-eharmony-linkedin-to-celebrate-breach-week"><strong>Last.FM</strong></a> have announced breaches that compromise millions of passwords in the past month alone. These breaches have leaked "<em>hashes</em>" of people's passwords, which make it trivial for attackers to find out the actual passwords <em>if they're not secure enough</em>.</p>
|
||||
|
||||
<hr class="clear" />
|
||||
<!--p>
|
||||
|
||||
1
Site/js/nivo-slider/README
Normal file
@@ -0,0 +1 @@
|
||||
Nivo Slider is "The Most Awesome jQuery Image Slider". See http://nivo.dev7studios.com for more info.
|
||||
35
Site/js/nivo-slider/demo/demo.html
Normal file
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Nivo Slider Demo</title>
|
||||
<link rel="stylesheet" href="../themes/default/default.css" type="text/css" media="screen" />
|
||||
<link rel="stylesheet" href="../nivo-slider.css" type="text/css" media="screen" />
|
||||
<link rel="stylesheet" href="style.css" type="text/css" media="screen" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<a href="http://dev7studios.com" id="dev7link" title="Go to dev7studios">dev7studios</a>
|
||||
|
||||
<div class="slider-wrapper theme-default">
|
||||
<div id="slider" class="nivoSlider">
|
||||
<img src="images/toystory.jpg" data-thumb="images/toystory.jpg" alt="" />
|
||||
<a href="http://dev7studios.com"><img src="images/up.jpg" data-thumb="images/up.jpg" alt="" title="This is an example of a caption" /></a>
|
||||
<img src="images/walle.jpg" data-thumb="images/walle.jpg" alt="" data-transition="slideInLeft" />
|
||||
<img src="images/nemo.jpg" data-thumb="images/nemo.jpg" alt="" title="#htmlcaption" />
|
||||
</div>
|
||||
<div id="htmlcaption" class="nivo-html-caption">
|
||||
<strong>This</strong> is an example of a <em>HTML</em> caption with <a href="#">a link</a>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script type="text/javascript" src="scripts/jquery-1.7.1.min.js"></script>
|
||||
<script type="text/javascript" src="../jquery.nivo.slider.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(window).load(function() {
|
||||
$('#slider').nivoSlider();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
Site/js/nivo-slider/demo/images/dev7logo.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Site/js/nivo-slider/demo/images/nemo.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
Site/js/nivo-slider/demo/images/toystory.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
Site/js/nivo-slider/demo/images/up.jpg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
Site/js/nivo-slider/demo/images/walle.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
4
Site/js/nivo-slider/demo/scripts/jquery-1.7.1.min.js
vendored
Normal file
103
Site/js/nivo-slider/demo/style.css
Normal file
@@ -0,0 +1,103 @@
|
||||
/*=================================*/
|
||||
/* Nivo Slider Demo
|
||||
/* November 2010
|
||||
/* By: Gilbert Pellegrom
|
||||
/* http://dev7studios.com
|
||||
/*=================================*/
|
||||
|
||||
/*====================*/
|
||||
/*=== Reset Styles ===*/
|
||||
/*====================*/
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, font, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td {
|
||||
margin:0;
|
||||
padding:0;
|
||||
border:0;
|
||||
outline:0;
|
||||
font-weight:inherit;
|
||||
font-style:inherit;
|
||||
font-size:100%;
|
||||
font-family:inherit;
|
||||
vertical-align:baseline;
|
||||
}
|
||||
body {
|
||||
line-height:1;
|
||||
color:black;
|
||||
background:white;
|
||||
}
|
||||
table {
|
||||
border-collapse:separate;
|
||||
border-spacing:0;
|
||||
}
|
||||
caption, th, td {
|
||||
text-align:left;
|
||||
font-weight:normal;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content:"";
|
||||
}
|
||||
blockquote, q {
|
||||
quotes:"" "";
|
||||
}
|
||||
/* HTML5 tags */
|
||||
header, section, footer,
|
||||
aside, nav, article, figure {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*===================*/
|
||||
/*=== Main Styles ===*/
|
||||
/*===================*/
|
||||
body {
|
||||
font:14px/1.6 Georgia, Palatino, Palatino Linotype, Times, Times New Roman, serif;
|
||||
color:#333;
|
||||
background:#eee;
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
color:blue;
|
||||
text-decoration:none;
|
||||
}
|
||||
a:hover, a:active {
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
#dev7link {
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:50px;
|
||||
background:url(images/dev7logo.png) no-repeat;
|
||||
width:60px;
|
||||
height:67px;
|
||||
border:0;
|
||||
display:block;
|
||||
text-indent:-9999px;
|
||||
}
|
||||
|
||||
.slider-wrapper {
|
||||
width: 80%;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.theme-default #slider {
|
||||
margin:100px auto 0 auto;
|
||||
}
|
||||
.theme-pascal.slider-wrapper,
|
||||
.theme-orman.slider-wrapper {
|
||||
margin-top:150px;
|
||||
}
|
||||
|
||||
/*====================*/
|
||||
/*=== Other Styles ===*/
|
||||
/*====================*/
|
||||
.clear {
|
||||
clear:both;
|
||||
}
|
||||
673
Site/js/nivo-slider/jquery.nivo.slider.js
Normal file
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* jQuery Nivo Slider v3.0.1
|
||||
* http://nivo.dev7studios.com
|
||||
*
|
||||
* Copyright 2012, Dev7studios
|
||||
* Free to use and abuse under the MIT license.
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
var NivoSlider = function(element, options){
|
||||
// Defaults are below
|
||||
var settings = $.extend({}, $.fn.nivoSlider.defaults, options);
|
||||
|
||||
// Useful variables. Play carefully.
|
||||
var vars = {
|
||||
currentSlide: 0,
|
||||
currentImage: '',
|
||||
totalSlides: 0,
|
||||
running: false,
|
||||
paused: false,
|
||||
stop: false,
|
||||
controlNavEl: false
|
||||
};
|
||||
|
||||
// Get this slider
|
||||
var slider = $(element);
|
||||
slider.data('nivo:vars', vars).addClass('nivoSlider');
|
||||
|
||||
// Find our slider children
|
||||
var kids = slider.children();
|
||||
kids.each(function() {
|
||||
var child = $(this);
|
||||
var link = '';
|
||||
if(!child.is('img')){
|
||||
if(child.is('a')){
|
||||
child.addClass('nivo-imageLink');
|
||||
link = child;
|
||||
}
|
||||
child = child.find('img:first');
|
||||
}
|
||||
// Get img width & height
|
||||
var childWidth = (childWidth === 0) ? child.attr('width') : child.width(),
|
||||
childHeight = (childHeight === 0) ? child.attr('height') : child.height();
|
||||
|
||||
if(link !== ''){
|
||||
link.css('display','none');
|
||||
}
|
||||
child.css('display','none');
|
||||
vars.totalSlides++;
|
||||
});
|
||||
|
||||
// If randomStart
|
||||
if(settings.randomStart){
|
||||
settings.startSlide = Math.floor(Math.random() * vars.totalSlides);
|
||||
}
|
||||
|
||||
// Set startSlide
|
||||
if(settings.startSlide > 0){
|
||||
if(settings.startSlide >= vars.totalSlides) { settings.startSlide = vars.totalSlides - 1; }
|
||||
vars.currentSlide = settings.startSlide;
|
||||
}
|
||||
|
||||
// Get initial image
|
||||
if($(kids[vars.currentSlide]).is('img')){
|
||||
vars.currentImage = $(kids[vars.currentSlide]);
|
||||
} else {
|
||||
vars.currentImage = $(kids[vars.currentSlide]).find('img:first');
|
||||
}
|
||||
|
||||
// Show initial link
|
||||
if($(kids[vars.currentSlide]).is('a')){
|
||||
$(kids[vars.currentSlide]).css('display','block');
|
||||
}
|
||||
|
||||
// Set first background
|
||||
var sliderImg = $('<img class="nivo-main-image" src="#" />');
|
||||
sliderImg.attr('src', vars.currentImage.attr('src')).show();
|
||||
slider.append(sliderImg);
|
||||
|
||||
// Detect Window Resize
|
||||
$(window).resize(function() {
|
||||
slider.children('img').width(slider.width());
|
||||
sliderImg.attr('src', vars.currentImage.attr('src'));
|
||||
sliderImg.stop().height('auto');
|
||||
$('.nivo-slice').remove();
|
||||
$('.nivo-box').remove();
|
||||
});
|
||||
|
||||
//Create caption
|
||||
slider.append($('<div class="nivo-caption"></div>'));
|
||||
|
||||
// Process caption function
|
||||
var processCaption = function(settings){
|
||||
var nivoCaption = $('.nivo-caption', slider);
|
||||
if(vars.currentImage.attr('title') != '' && vars.currentImage.attr('title') != undefined){
|
||||
var title = vars.currentImage.attr('title');
|
||||
if(title.substr(0,1) == '#') title = $(title).html();
|
||||
|
||||
if(nivoCaption.css('display') == 'block'){
|
||||
setTimeout(function(){
|
||||
nivoCaption.html(title);
|
||||
}, settings.animSpeed);
|
||||
} else {
|
||||
nivoCaption.html(title);
|
||||
nivoCaption.stop().fadeIn(settings.animSpeed);
|
||||
}
|
||||
} else {
|
||||
nivoCaption.stop().fadeOut(settings.animSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
//Process initial caption
|
||||
processCaption(settings);
|
||||
|
||||
// In the words of Super Mario "let's a go!"
|
||||
var timer = 0;
|
||||
if(!settings.manualAdvance && kids.length > 1){
|
||||
timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime);
|
||||
}
|
||||
|
||||
// Add Direction nav
|
||||
if(settings.directionNav){
|
||||
slider.append('<div class="nivo-directionNav"><a class="nivo-prevNav">'+ settings.prevText +'</a><a class="nivo-nextNav">'+ settings.nextText +'</a></div>');
|
||||
|
||||
// Hide Direction nav
|
||||
if(settings.directionNavHide){
|
||||
$('.nivo-directionNav', slider).hide();
|
||||
slider.hover(function(){
|
||||
$('.nivo-directionNav', slider).show();
|
||||
}, function(){
|
||||
$('.nivo-directionNav', slider).hide();
|
||||
});
|
||||
}
|
||||
|
||||
$('a.nivo-prevNav', slider).live('click', function(){
|
||||
if(vars.running) { return false; }
|
||||
clearInterval(timer);
|
||||
timer = '';
|
||||
vars.currentSlide -= 2;
|
||||
nivoRun(slider, kids, settings, 'prev');
|
||||
});
|
||||
|
||||
$('a.nivo-nextNav', slider).live('click', function(){
|
||||
if(vars.running) { return false; }
|
||||
clearInterval(timer);
|
||||
timer = '';
|
||||
nivoRun(slider, kids, settings, 'next');
|
||||
});
|
||||
}
|
||||
|
||||
// Add Control nav
|
||||
if(settings.controlNav){
|
||||
vars.controlNavEl = $('<div class="nivo-controlNav"></div>');
|
||||
slider.after(vars.controlNavEl);
|
||||
for(var i = 0; i < kids.length; i++){
|
||||
if(settings.controlNavThumbs){
|
||||
vars.controlNavEl.addClass('nivo-thumbs-enabled');
|
||||
var child = kids.eq(i);
|
||||
if(!child.is('img')){
|
||||
child = child.find('img:first');
|
||||
}
|
||||
if(child.attr('data-thumb')) vars.controlNavEl.append('<a class="nivo-control" rel="'+ i +'"><img src="'+ child.attr('data-thumb') +'" alt="" /></a>');
|
||||
} else {
|
||||
vars.controlNavEl.append('<a class="nivo-control" rel="'+ i +'">'+ (i + 1) +'</a>');
|
||||
}
|
||||
}
|
||||
|
||||
//Set initial active link
|
||||
$('a:eq('+ vars.currentSlide +')', vars.controlNavEl).addClass('active');
|
||||
|
||||
$('a', vars.controlNavEl).bind('click', function(){
|
||||
if(vars.running) return false;
|
||||
if($(this).hasClass('active')) return false;
|
||||
clearInterval(timer);
|
||||
timer = '';
|
||||
sliderImg.attr('src', vars.currentImage.attr('src'));
|
||||
vars.currentSlide = $(this).attr('rel') - 1;
|
||||
nivoRun(slider, kids, settings, 'control');
|
||||
});
|
||||
}
|
||||
|
||||
//For pauseOnHover setting
|
||||
if(settings.pauseOnHover){
|
||||
slider.hover(function(){
|
||||
vars.paused = true;
|
||||
clearInterval(timer);
|
||||
timer = '';
|
||||
}, function(){
|
||||
vars.paused = false;
|
||||
// Restart the timer
|
||||
if(timer === '' && !settings.manualAdvance){
|
||||
timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Event when Animation finishes
|
||||
slider.bind('nivo:animFinished', function(){
|
||||
sliderImg.attr('src', vars.currentImage.attr('src'));
|
||||
vars.running = false;
|
||||
// Hide child links
|
||||
$(kids).each(function(){
|
||||
if($(this).is('a')){
|
||||
$(this).css('display','none');
|
||||
}
|
||||
});
|
||||
// Show current link
|
||||
if($(kids[vars.currentSlide]).is('a')){
|
||||
$(kids[vars.currentSlide]).css('display','block');
|
||||
}
|
||||
// Restart the timer
|
||||
if(timer === '' && !vars.paused && !settings.manualAdvance){
|
||||
timer = setInterval(function(){ nivoRun(slider, kids, settings, false); }, settings.pauseTime);
|
||||
}
|
||||
// Trigger the afterChange callback
|
||||
settings.afterChange.call(this);
|
||||
});
|
||||
|
||||
// Add slices for slice animations
|
||||
var createSlices = function(slider, settings, vars) {
|
||||
if($(vars.currentImage).parent().is('a')) $(vars.currentImage).parent().css('display','block');
|
||||
$('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').width(slider.width()).css('visibility', 'hidden').show();
|
||||
var sliceHeight = ($('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').parent().is('a')) ? $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').parent().height() : $('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').height();
|
||||
|
||||
for(var i = 0; i < settings.slices; i++){
|
||||
var sliceWidth = Math.round(slider.width()/settings.slices);
|
||||
|
||||
if(i === settings.slices-1){
|
||||
slider.append(
|
||||
$('<div class="nivo-slice" name="'+i+'"><img src="'+ vars.currentImage.attr('src') +'" style="position:absolute; width:'+ slider.width() +'px; height:auto; display:block !important; top:0; left:-'+ ((sliceWidth + (i * sliceWidth)) - sliceWidth) +'px;" /></div>').css({
|
||||
left:(sliceWidth*i)+'px',
|
||||
width:(slider.width()-(sliceWidth*i))+'px',
|
||||
height:sliceHeight+'px',
|
||||
opacity:'0',
|
||||
overflow:'hidden'
|
||||
})
|
||||
);
|
||||
} else {
|
||||
slider.append(
|
||||
$('<div class="nivo-slice" name="'+i+'"><img src="'+ vars.currentImage.attr('src') +'" style="position:absolute; width:'+ slider.width() +'px; height:auto; display:block !important; top:0; left:-'+ ((sliceWidth + (i * sliceWidth)) - sliceWidth) +'px;" /></div>').css({
|
||||
left:(sliceWidth*i)+'px',
|
||||
width:sliceWidth+'px',
|
||||
height:sliceHeight+'px',
|
||||
opacity:'0',
|
||||
overflow:'hidden'
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$('.nivo-slice', slider).height(sliceHeight);
|
||||
sliderImg.stop().animate({
|
||||
height: $(vars.currentImage).height()
|
||||
}, settings.animSpeed);
|
||||
};
|
||||
|
||||
// Add boxes for box animations
|
||||
var createBoxes = function(slider, settings, vars){
|
||||
if($(vars.currentImage).parent().is('a')) $(vars.currentImage).parent().css('display','block');
|
||||
$('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').width(slider.width()).css('visibility', 'hidden').show();
|
||||
var boxWidth = Math.round(slider.width()/settings.boxCols),
|
||||
boxHeight = Math.round($('img[src="'+ vars.currentImage.attr('src') +'"]', slider).not('.nivo-main-image,.nivo-control img').height() / settings.boxRows);
|
||||
|
||||
|
||||
for(var rows = 0; rows < settings.boxRows; rows++){
|
||||
for(var cols = 0; cols < settings.boxCols; cols++){
|
||||
if(cols === settings.boxCols-1){
|
||||
slider.append(
|
||||
$('<div class="nivo-box" name="'+ cols +'" rel="'+ rows +'"><img src="'+ vars.currentImage.attr('src') +'" style="position:absolute; width:'+ slider.width() +'px; height:auto; display:block; top:-'+ (boxHeight*rows) +'px; left:-'+ (boxWidth*cols) +'px;" /></div>').css({
|
||||
opacity:0,
|
||||
left:(boxWidth*cols)+'px',
|
||||
top:(boxHeight*rows)+'px',
|
||||
width:(slider.width()-(boxWidth*cols))+'px'
|
||||
|
||||
})
|
||||
);
|
||||
$('.nivo-box[name="'+ cols +'"]', slider).height($('.nivo-box[name="'+ cols +'"] img', slider).height()+'px');
|
||||
} else {
|
||||
slider.append(
|
||||
$('<div class="nivo-box" name="'+ cols +'" rel="'+ rows +'"><img src="'+ vars.currentImage.attr('src') +'" style="position:absolute; width:'+ slider.width() +'px; height:auto; display:block; top:-'+ (boxHeight*rows) +'px; left:-'+ (boxWidth*cols) +'px;" /></div>').css({
|
||||
opacity:0,
|
||||
left:(boxWidth*cols)+'px',
|
||||
top:(boxHeight*rows)+'px',
|
||||
width:boxWidth+'px'
|
||||
})
|
||||
);
|
||||
$('.nivo-box[name="'+ cols +'"]', slider).height($('.nivo-box[name="'+ cols +'"] img', slider).height()+'px');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sliderImg.stop().animate({
|
||||
height: $(vars.currentImage).height()
|
||||
}, settings.animSpeed);
|
||||
};
|
||||
|
||||
// Private run method
|
||||
var nivoRun = function(slider, kids, settings, nudge){
|
||||
// Get our vars
|
||||
var vars = slider.data('nivo:vars');
|
||||
|
||||
// Trigger the lastSlide callback
|
||||
if(vars && (vars.currentSlide === vars.totalSlides - 1)){
|
||||
settings.lastSlide.call(this);
|
||||
}
|
||||
|
||||
// Stop
|
||||
if((!vars || vars.stop) && !nudge) { return false; }
|
||||
|
||||
// Trigger the beforeChange callback
|
||||
settings.beforeChange.call(this);
|
||||
|
||||
// Set current background before change
|
||||
if(!nudge){
|
||||
sliderImg.attr('src', vars.currentImage.attr('src'));
|
||||
} else {
|
||||
if(nudge === 'prev'){
|
||||
sliderImg.attr('src', vars.currentImage.attr('src'));
|
||||
}
|
||||
if(nudge === 'next'){
|
||||
sliderImg.attr('src', vars.currentImage.attr('src'));
|
||||
}
|
||||
}
|
||||
|
||||
vars.currentSlide++;
|
||||
// Trigger the slideshowEnd callback
|
||||
if(vars.currentSlide === vars.totalSlides){
|
||||
vars.currentSlide = 0;
|
||||
settings.slideshowEnd.call(this);
|
||||
}
|
||||
if(vars.currentSlide < 0) { vars.currentSlide = (vars.totalSlides - 1); }
|
||||
// Set vars.currentImage
|
||||
if($(kids[vars.currentSlide]).is('img')){
|
||||
vars.currentImage = $(kids[vars.currentSlide]);
|
||||
} else {
|
||||
vars.currentImage = $(kids[vars.currentSlide]).find('img:first');
|
||||
}
|
||||
|
||||
// Set active links
|
||||
if(settings.controlNav){
|
||||
$('a', vars.controlNavEl).removeClass('active');
|
||||
$('a:eq('+ vars.currentSlide +')', vars.controlNavEl).addClass('active');
|
||||
}
|
||||
|
||||
// Process caption
|
||||
processCaption(settings);
|
||||
|
||||
// Remove any slices from last transition
|
||||
$('.nivo-slice', slider).remove();
|
||||
|
||||
// Remove any boxes from last transition
|
||||
$('.nivo-box', slider).remove();
|
||||
|
||||
var currentEffect = settings.effect,
|
||||
anims = '';
|
||||
|
||||
// Generate random effect
|
||||
if(settings.effect === 'random'){
|
||||
anims = new Array('sliceDownRight','sliceDownLeft','sliceUpRight','sliceUpLeft','sliceUpDown','sliceUpDownLeft','fold','fade',
|
||||
'boxRandom','boxRain','boxRainReverse','boxRainGrow','boxRainGrowReverse');
|
||||
currentEffect = anims[Math.floor(Math.random()*(anims.length + 1))];
|
||||
if(currentEffect === undefined) { currentEffect = 'fade'; }
|
||||
}
|
||||
|
||||
// Run random effect from specified set (eg: effect:'fold,fade')
|
||||
if(settings.effect.indexOf(',') !== -1){
|
||||
anims = settings.effect.split(',');
|
||||
currentEffect = anims[Math.floor(Math.random()*(anims.length))];
|
||||
if(currentEffect === undefined) { currentEffect = 'fade'; }
|
||||
}
|
||||
|
||||
// Custom transition as defined by "data-transition" attribute
|
||||
if(vars.currentImage.attr('data-transition')){
|
||||
currentEffect = vars.currentImage.attr('data-transition');
|
||||
}
|
||||
|
||||
// Run effects
|
||||
vars.running = true;
|
||||
var timeBuff = 0,
|
||||
i = 0,
|
||||
slices = '',
|
||||
firstSlice = '',
|
||||
totalBoxes = '',
|
||||
boxes = '';
|
||||
|
||||
if(currentEffect === 'sliceDown' || currentEffect === 'sliceDownRight' || currentEffect === 'sliceDownLeft'){
|
||||
createSlices(slider, settings, vars);
|
||||
timeBuff = 0;
|
||||
i = 0;
|
||||
slices = $('.nivo-slice', slider);
|
||||
if(currentEffect === 'sliceDownLeft') { slices = $('.nivo-slice', slider)._reverse(); }
|
||||
|
||||
slices.each(function(){
|
||||
var slice = $(this);
|
||||
slice.css({ 'top': '0px' });
|
||||
if(i === settings.slices-1){
|
||||
setTimeout(function(){
|
||||
slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
}, (100 + timeBuff));
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
slice.animate({opacity:'1.0' }, settings.animSpeed);
|
||||
}, (100 + timeBuff));
|
||||
}
|
||||
timeBuff += 50;
|
||||
i++;
|
||||
});
|
||||
} else if(currentEffect === 'sliceUp' || currentEffect === 'sliceUpRight' || currentEffect === 'sliceUpLeft'){
|
||||
createSlices(slider, settings, vars);
|
||||
timeBuff = 0;
|
||||
i = 0;
|
||||
slices = $('.nivo-slice', slider);
|
||||
if(currentEffect === 'sliceUpLeft') { slices = $('.nivo-slice', slider)._reverse(); }
|
||||
|
||||
slices.each(function(){
|
||||
var slice = $(this);
|
||||
slice.css({ 'bottom': '0px' });
|
||||
if(i === settings.slices-1){
|
||||
setTimeout(function(){
|
||||
slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
}, (100 + timeBuff));
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
slice.animate({opacity:'1.0' }, settings.animSpeed);
|
||||
}, (100 + timeBuff));
|
||||
}
|
||||
timeBuff += 50;
|
||||
i++;
|
||||
});
|
||||
} else if(currentEffect === 'sliceUpDown' || currentEffect === 'sliceUpDownRight' || currentEffect === 'sliceUpDownLeft'){
|
||||
createSlices(slider, settings, vars);
|
||||
timeBuff = 0;
|
||||
i = 0;
|
||||
var v = 0;
|
||||
slices = $('.nivo-slice', slider);
|
||||
if(currentEffect === 'sliceUpDownLeft') { slices = $('.nivo-slice', slider)._reverse(); }
|
||||
|
||||
slices.each(function(){
|
||||
var slice = $(this);
|
||||
if(i === 0){
|
||||
slice.css('top','0px');
|
||||
i++;
|
||||
} else {
|
||||
slice.css('bottom','0px');
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if(v === settings.slices-1){
|
||||
setTimeout(function(){
|
||||
slice.animate({opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
}, (100 + timeBuff));
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
slice.animate({opacity:'1.0' }, settings.animSpeed);
|
||||
}, (100 + timeBuff));
|
||||
}
|
||||
timeBuff += 50;
|
||||
v++;
|
||||
});
|
||||
} else if(currentEffect === 'fold'){
|
||||
createSlices(slider, settings, vars);
|
||||
timeBuff = 0;
|
||||
i = 0;
|
||||
|
||||
$('.nivo-slice', slider).each(function(){
|
||||
var slice = $(this);
|
||||
var origWidth = slice.width();
|
||||
slice.css({ top:'0px', width:'0px' });
|
||||
if(i === settings.slices-1){
|
||||
setTimeout(function(){
|
||||
slice.animate({ width:origWidth, opacity:'1.0' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
}, (100 + timeBuff));
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
slice.animate({ width:origWidth, opacity:'1.0' }, settings.animSpeed);
|
||||
}, (100 + timeBuff));
|
||||
}
|
||||
timeBuff += 50;
|
||||
i++;
|
||||
});
|
||||
} else if(currentEffect === 'fade'){
|
||||
createSlices(slider, settings, vars);
|
||||
|
||||
firstSlice = $('.nivo-slice:first', slider);
|
||||
firstSlice.css({
|
||||
'width': slider.width() + 'px'
|
||||
});
|
||||
|
||||
firstSlice.animate({ opacity:'1.0' }, (settings.animSpeed*2), '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
} else if(currentEffect === 'slideInRight'){
|
||||
createSlices(slider, settings, vars);
|
||||
|
||||
firstSlice = $('.nivo-slice:first', slider);
|
||||
firstSlice.css({
|
||||
'width': '0px',
|
||||
'opacity': '1'
|
||||
});
|
||||
|
||||
firstSlice.animate({ width: slider.width() + 'px' }, (settings.animSpeed*2), '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
} else if(currentEffect === 'slideInLeft'){
|
||||
createSlices(slider, settings, vars);
|
||||
|
||||
firstSlice = $('.nivo-slice:first', slider);
|
||||
firstSlice.css({
|
||||
'width': '0px',
|
||||
'opacity': '1',
|
||||
'left': '',
|
||||
'right': '0px'
|
||||
});
|
||||
|
||||
firstSlice.animate({ width: slider.width() + 'px' }, (settings.animSpeed*2), '', function(){
|
||||
// Reset positioning
|
||||
firstSlice.css({
|
||||
'left': '0px',
|
||||
'right': ''
|
||||
});
|
||||
slider.trigger('nivo:animFinished');
|
||||
});
|
||||
} else if(currentEffect === 'boxRandom'){
|
||||
createBoxes(slider, settings, vars);
|
||||
|
||||
totalBoxes = settings.boxCols * settings.boxRows;
|
||||
i = 0;
|
||||
timeBuff = 0;
|
||||
|
||||
boxes = shuffle($('.nivo-box', slider));
|
||||
boxes.each(function(){
|
||||
var box = $(this);
|
||||
if(i === totalBoxes-1){
|
||||
setTimeout(function(){
|
||||
box.animate({ opacity:'1' }, settings.animSpeed, '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
}, (100 + timeBuff));
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
box.animate({ opacity:'1' }, settings.animSpeed);
|
||||
}, (100 + timeBuff));
|
||||
}
|
||||
timeBuff += 20;
|
||||
i++;
|
||||
});
|
||||
} else if(currentEffect === 'boxRain' || currentEffect === 'boxRainReverse' || currentEffect === 'boxRainGrow' || currentEffect === 'boxRainGrowReverse'){
|
||||
createBoxes(slider, settings, vars);
|
||||
|
||||
totalBoxes = settings.boxCols * settings.boxRows;
|
||||
i = 0;
|
||||
timeBuff = 0;
|
||||
|
||||
// Split boxes into 2D array
|
||||
var rowIndex = 0;
|
||||
var colIndex = 0;
|
||||
var box2Darr = [];
|
||||
box2Darr[rowIndex] = [];
|
||||
boxes = $('.nivo-box', slider);
|
||||
if(currentEffect === 'boxRainReverse' || currentEffect === 'boxRainGrowReverse'){
|
||||
boxes = $('.nivo-box', slider)._reverse();
|
||||
}
|
||||
boxes.each(function(){
|
||||
box2Darr[rowIndex][colIndex] = $(this);
|
||||
colIndex++;
|
||||
if(colIndex === settings.boxCols){
|
||||
rowIndex++;
|
||||
colIndex = 0;
|
||||
box2Darr[rowIndex] = [];
|
||||
}
|
||||
});
|
||||
|
||||
// Run animation
|
||||
for(var cols = 0; cols < (settings.boxCols * 2); cols++){
|
||||
var prevCol = cols;
|
||||
for(var rows = 0; rows < settings.boxRows; rows++){
|
||||
if(prevCol >= 0 && prevCol < settings.boxCols){
|
||||
/* Due to some weird JS bug with loop vars
|
||||
being used in setTimeout, this is wrapped
|
||||
with an anonymous function call */
|
||||
(function(row, col, time, i, totalBoxes) {
|
||||
var box = $(box2Darr[row][col]);
|
||||
var w = box.width();
|
||||
var h = box.height();
|
||||
if(currentEffect === 'boxRainGrow' || currentEffect === 'boxRainGrowReverse'){
|
||||
box.width(0).height(0);
|
||||
}
|
||||
if(i === totalBoxes-1){
|
||||
setTimeout(function(){
|
||||
box.animate({ opacity:'1', width:w, height:h }, settings.animSpeed/1.3, '', function(){ slider.trigger('nivo:animFinished'); });
|
||||
}, (100 + time));
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
box.animate({ opacity:'1', width:w, height:h }, settings.animSpeed/1.3);
|
||||
}, (100 + time));
|
||||
}
|
||||
})(rows, prevCol, timeBuff, i, totalBoxes);
|
||||
i++;
|
||||
}
|
||||
prevCol--;
|
||||
}
|
||||
timeBuff += 100;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Shuffle an array
|
||||
var shuffle = function(arr){
|
||||
for(var j, x, i = arr.length; i; j = parseInt(Math.random() * i, 10), x = arr[--i], arr[i] = arr[j], arr[j] = x);
|
||||
return arr;
|
||||
};
|
||||
|
||||
// For debugging
|
||||
var trace = function(msg){
|
||||
if(this.console && typeof console.log !== 'undefined') { console.log(msg); }
|
||||
};
|
||||
|
||||
// Start / Stop
|
||||
this.stop = function(){
|
||||
if(!$(element).data('nivo:vars').stop){
|
||||
$(element).data('nivo:vars').stop = true;
|
||||
trace('Stop Slider');
|
||||
}
|
||||
};
|
||||
|
||||
this.start = function(){
|
||||
if($(element).data('nivo:vars').stop){
|
||||
$(element).data('nivo:vars').stop = false;
|
||||
trace('Start Slider');
|
||||
}
|
||||
};
|
||||
|
||||
// Trigger the afterLoad callback
|
||||
settings.afterLoad.call(this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
$.fn.nivoSlider = function(options) {
|
||||
return this.each(function(key, value){
|
||||
var element = $(this);
|
||||
// Return early if this element already has a plugin instance
|
||||
if (element.data('nivoslider')) { return element.data('nivoslider'); }
|
||||
// Pass options to plugin constructor
|
||||
var nivoslider = new NivoSlider(this, options);
|
||||
// Store plugin object in this element's data
|
||||
element.data('nivoslider', nivoslider);
|
||||
});
|
||||
};
|
||||
|
||||
//Default settings
|
||||
$.fn.nivoSlider.defaults = {
|
||||
effect: 'random',
|
||||
slices: 15,
|
||||
boxCols: 8,
|
||||
boxRows: 4,
|
||||
animSpeed: 500,
|
||||
pauseTime: 3000,
|
||||
startSlide: 0,
|
||||
directionNav: true,
|
||||
directionNavHide: true,
|
||||
controlNav: true,
|
||||
controlNavThumbs: false,
|
||||
pauseOnHover: true,
|
||||
manualAdvance: false,
|
||||
prevText: 'Prev',
|
||||
nextText: 'Next',
|
||||
randomStart: false,
|
||||
beforeChange: function(){},
|
||||
afterChange: function(){},
|
||||
slideshowEnd: function(){},
|
||||
lastSlide: function(){},
|
||||
afterLoad: function(){}
|
||||
};
|
||||
|
||||
$.fn._reverse = [].reverse;
|
||||
|
||||
})(jQuery);
|
||||
10
Site/js/nivo-slider/jquery.nivo.slider.pack.js
Normal file
22
Site/js/nivo-slider/license.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2010-2012 Dev7studios
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
109
Site/js/nivo-slider/nivo-slider.css
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* jQuery Nivo Slider v3.0.1
|
||||
* http://nivo.dev7studios.com
|
||||
*
|
||||
* Copyright 2012, Dev7studios
|
||||
* Free to use and abuse under the MIT license.
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
*/
|
||||
|
||||
/* The Nivo Slider styles */
|
||||
.nivoSlider {
|
||||
position:relative;
|
||||
width:100%;
|
||||
height:auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
.nivoSlider img {
|
||||
position:absolute;
|
||||
top:0px;
|
||||
left:0px;
|
||||
}
|
||||
.nivo-main-image {
|
||||
display: block !important;
|
||||
position: relative !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/* If an image is wrapped in a link */
|
||||
.nivoSlider a.nivo-imageLink {
|
||||
position:absolute;
|
||||
top:0px;
|
||||
left:0px;
|
||||
width:100%;
|
||||
height:100%;
|
||||
border:0;
|
||||
padding:0;
|
||||
margin:0;
|
||||
z-index:6;
|
||||
display:none;
|
||||
}
|
||||
/* The slices and boxes in the Slider */
|
||||
.nivo-slice {
|
||||
display:block;
|
||||
position:absolute;
|
||||
z-index:5;
|
||||
height:100%;
|
||||
top:0;
|
||||
}
|
||||
.nivo-box {
|
||||
display:block;
|
||||
position:absolute;
|
||||
z-index:5;
|
||||
overflow:hidden;
|
||||
}
|
||||
.nivo-box img { display:block; }
|
||||
|
||||
/* Caption styles */
|
||||
.nivo-caption {
|
||||
position:absolute;
|
||||
left:0px;
|
||||
bottom:0px;
|
||||
background:#000;
|
||||
color:#fff;
|
||||
width:100%;
|
||||
z-index:8;
|
||||
padding: 5px 10px;
|
||||
opacity: 0.8;
|
||||
overflow: hidden;
|
||||
display: none;
|
||||
-moz-opacity: 0.8;
|
||||
filter:alpha(opacity=8);
|
||||
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
|
||||
-moz-box-sizing: border-box; /* Firefox, other Gecko */
|
||||
box-sizing: border-box; /* Opera/IE 8+ */
|
||||
}
|
||||
.nivo-caption p {
|
||||
padding:5px;
|
||||
margin:0;
|
||||
}
|
||||
.nivo-caption a {
|
||||
display:inline !important;
|
||||
}
|
||||
.nivo-html-caption {
|
||||
display:none;
|
||||
}
|
||||
/* Direction nav styles (e.g. Next & Prev) */
|
||||
.nivo-directionNav a {
|
||||
position:absolute;
|
||||
top:45%;
|
||||
z-index:9;
|
||||
cursor:pointer;
|
||||
}
|
||||
.nivo-prevNav {
|
||||
left:0px;
|
||||
}
|
||||
.nivo-nextNav {
|
||||
right:0px;
|
||||
}
|
||||
/* Control nav styles (e.g. 1,2,3...) */
|
||||
.nivo-controlNav {
|
||||
text-align:center;
|
||||
padding: 15px 0;
|
||||
}
|
||||
.nivo-controlNav a {
|
||||
cursor:pointer;
|
||||
}
|
||||
.nivo-controlNav a.active {
|
||||
font-weight:bold;
|
||||
}
|
||||
BIN
Site/js/nivo-slider/themes/default/arrows.png
Normal file
|
After Width: | Height: | Size: 824 B |
BIN
Site/js/nivo-slider/themes/default/bullets.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
87
Site/js/nivo-slider/themes/default/default.css
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Skin Name: Nivo Slider Default Theme
|
||||
Skin URI: http://nivo.dev7studios.com
|
||||
Skin Type: flexible
|
||||
Description: The default skin for the Nivo Slider.
|
||||
Version: 1.2
|
||||
Author: Gilbert Pellegrom
|
||||
Author URI: http://dev7studios.com
|
||||
*/
|
||||
|
||||
.theme-default .nivoSlider {
|
||||
position:relative;
|
||||
background:#fff url(loading.gif) no-repeat 50% 50%;
|
||||
margin-bottom:50px;
|
||||
-webkit-box-shadow: 0px 1px 5px 0px #4a4a4a;
|
||||
-moz-box-shadow: 0px 1px 5px 0px #4a4a4a;
|
||||
box-shadow: 0px 1px 5px 0px #4a4a4a;
|
||||
}
|
||||
.theme-default .nivoSlider img {
|
||||
position:absolute;
|
||||
top:0px;
|
||||
left:0px;
|
||||
display:none;
|
||||
}
|
||||
.theme-default .nivoSlider a {
|
||||
border:0;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.theme-default .nivo-controlNav {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
.theme-default .nivo-controlNav a {
|
||||
display:inline-block;
|
||||
width:22px;
|
||||
height:22px;
|
||||
background:url(bullets.png) no-repeat;
|
||||
text-indent:-9999px;
|
||||
border:0;
|
||||
margin: 0 2px;
|
||||
}
|
||||
.theme-default .nivo-controlNav a.active {
|
||||
background-position:0 -22px;
|
||||
}
|
||||
|
||||
.theme-default .nivo-directionNav a {
|
||||
display:block;
|
||||
width:30px;
|
||||
height:30px;
|
||||
background:url(arrows.png) no-repeat;
|
||||
text-indent:-9999px;
|
||||
border:0;
|
||||
}
|
||||
.theme-default a.nivo-nextNav {
|
||||
background-position:-30px 0;
|
||||
right:15px;
|
||||
}
|
||||
.theme-default a.nivo-prevNav {
|
||||
left:15px;
|
||||
}
|
||||
|
||||
.theme-default .nivo-caption {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
}
|
||||
.theme-default .nivo-caption a {
|
||||
color:#fff;
|
||||
border-bottom:1px dotted #fff;
|
||||
}
|
||||
.theme-default .nivo-caption a:hover {
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.theme-default .nivo-controlNav.nivo-thumbs-enabled {
|
||||
width: 100%;
|
||||
}
|
||||
.theme-default .nivo-controlNav.nivo-thumbs-enabled a {
|
||||
width: auto;
|
||||
height: auto;
|
||||
background: none;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.theme-default .nivo-controlNav.nivo-thumbs-enabled img {
|
||||
display: block;
|
||||
width: 120px;
|
||||
height: auto;
|
||||
}
|
||||
BIN
Site/js/nivo-slider/themes/default/loading.gif
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
@@ -31,13 +31,13 @@
|
||||
<body>
|
||||
<header>
|
||||
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984"><img src="img/appstore.png" /></a>
|
||||
<h1><a href="index.html"><img class="logo" src="img/iTunesArtwork-Bare.png" /> Master Password</a></h1>
|
||||
<div class="divider"></div>
|
||||
|
||||
</header>
|
||||
<div id="fixedheader">
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore-small.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984"><img src="img/appstore-small.png" /></a>
|
||||
<h2><a href="index.html">Master Password</a></h2>
|
||||
</div>
|
||||
<!--a href="http://bit.ly/vNN5Zi" onclick="_gaq.push(['_trackPageview', '/outbound/testflight']);" id="ribbon"></a-->
|
||||
|
||||
@@ -85,10 +85,10 @@
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984"><img src="img/appstore.png" /></a>
|
||||
<header>
|
||||
|
||||
<a class="appstore" href="http://itunes.com/apps/MasterPassword"><img src="img/appstore.png" /></a>
|
||||
<a class="appstore" href="http://itunes.apple.com/app/id510296984"><img src="img/appstore.png" /></a>
|
||||
<h1><a href="index.html"><img class="logo" src="img/iTunesArtwork-Bare.png" /> Master Password</a></h1>
|
||||
<div class="divider"></div>
|
||||
|
||||
|
||||
22
Tests/Tests-Info.plist
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.lyndir.lhunath.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
||||
10
Tests/Tests-Prefix.pch
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Prefix header for all source files of the 'Tests' target in the 'Tests' project
|
||||
//
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#import "MasterPassword-Prefix.pch"
|
||||
13
Tests/Tests.h
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// Tests.h
|
||||
// Tests
|
||||
//
|
||||
// Created by Maarten Billemont on 04/07/12.
|
||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SenTestingKit/SenTestingKit.h>
|
||||
|
||||
@interface Tests : SenTestCase
|
||||
|
||||
@end
|
||||
45
Tests/Tests.m
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// Tests.m
|
||||
// Tests
|
||||
//
|
||||
// Created by Maarten Billemont on 04/07/12.
|
||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Tests.h"
|
||||
|
||||
@implementation Tests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
dbg(@"======================= TEST SET-UP ======================");
|
||||
[PearlLogger get].autoprintLevel = PearlLogLevelTrace;
|
||||
|
||||
[super setUp];
|
||||
|
||||
// Set-up code here.
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
dbg(@"===================== TEST TEAR-DOWN =====================");
|
||||
// Tear-down code here.
|
||||
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testAlgorithm
|
||||
{
|
||||
NSString *masterPassword = @"test-mp";
|
||||
NSString *username = @"test-user";
|
||||
NSString *siteName = @"test-site";
|
||||
MPElementType siteType = MPElementTypeGeneratedLong;
|
||||
uint32_t siteCounter = 42;
|
||||
|
||||
NSString *sitePassword = MPCalculateContent( siteType, siteName, keyForPassword( masterPassword, username ), siteCounter );
|
||||
|
||||
inf( @"master password: %@, username: %@\nsite name: %@, site type: %@, site counter: %d\n => site password: %@",
|
||||
masterPassword, username, siteName, NSStringFromMPElementType(siteType), siteCounter, sitePassword );
|
||||
}
|
||||
|
||||
@end
|
||||