├── .gitignore
├── LICENSE.md
├── Package.swift
├── PasswordRules.xcodeproj
├── PasswordRulesTests_Info.plist
├── PasswordRules_Info.plist
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── xcshareddata
│ └── xcschemes
│ └── PasswordRules-Package.xcscheme
├── README.md
├── Sources
└── PasswordRules
│ └── PasswordRules.swift
└── Tests
├── LinuxMain.swift
└── PasswordRulesTests
├── PasswordRulesTests.swift
└── XCTestManifests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright 2018 Read Evaluate Press, LLC
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the "Software"),
5 | to deal in the Software without restriction, including without limitation
6 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the
8 | Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 | DEALINGS IN THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:4.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "PasswordRules",
8 | products: [
9 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
10 | .library(
11 | name: "PasswordRules",
12 | targets: ["PasswordRules"]),
13 | ],
14 | dependencies: [
15 | // Dependencies declare other packages that this package depends on.
16 | // .package(url: /* package url */, from: "1.0.0"),
17 | ],
18 | targets: [
19 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
20 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
21 | .target(
22 | name: "PasswordRules",
23 | dependencies: []),
24 | .testTarget(
25 | name: "PasswordRulesTests",
26 | dependencies: ["PasswordRules"]),
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/PasswordRules.xcodeproj/PasswordRulesTests_Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | BNDL
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/PasswordRules.xcodeproj/PasswordRules_Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | FMWK
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/PasswordRules.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXAggregateTarget section */
10 | "PasswordRules::PasswordRulesPackageTests::ProductTarget" /* PasswordRulesPackageTests */ = {
11 | isa = PBXAggregateTarget;
12 | buildConfigurationList = OBJ_31 /* Build configuration list for PBXAggregateTarget "PasswordRulesPackageTests" */;
13 | buildPhases = (
14 | );
15 | dependencies = (
16 | OBJ_34 /* PBXTargetDependency */,
17 | );
18 | name = PasswordRulesPackageTests;
19 | productName = PasswordRulesPackageTests;
20 | };
21 | /* End PBXAggregateTarget section */
22 |
23 | /* Begin PBXBuildFile section */
24 | OBJ_22 /* PasswordRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* PasswordRules.swift */; };
25 | OBJ_29 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; };
26 | OBJ_40 /* PasswordRulesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_12 /* PasswordRulesTests.swift */; };
27 | OBJ_41 /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* XCTestManifests.swift */; };
28 | OBJ_43 /* PasswordRules.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "PasswordRules::PasswordRules::Product" /* PasswordRules.framework */; };
29 | /* End PBXBuildFile section */
30 |
31 | /* Begin PBXContainerItemProxy section */
32 | F8532BFD210F1AA300A3A56D /* PBXContainerItemProxy */ = {
33 | isa = PBXContainerItemProxy;
34 | containerPortal = OBJ_1 /* Project object */;
35 | proxyType = 1;
36 | remoteGlobalIDString = "PasswordRules::PasswordRules";
37 | remoteInfo = PasswordRules;
38 | };
39 | F8532BFE210F1AA400A3A56D /* PBXContainerItemProxy */ = {
40 | isa = PBXContainerItemProxy;
41 | containerPortal = OBJ_1 /* Project object */;
42 | proxyType = 1;
43 | remoteGlobalIDString = "PasswordRules::PasswordRulesTests";
44 | remoteInfo = PasswordRulesTests;
45 | };
46 | /* End PBXContainerItemProxy section */
47 |
48 | /* Begin PBXFileReference section */
49 | OBJ_12 /* PasswordRulesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordRulesTests.swift; sourceTree = ""; };
50 | OBJ_13 /* XCTestManifests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestManifests.swift; sourceTree = ""; };
51 | OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; };
52 | OBJ_9 /* PasswordRules.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordRules.swift; sourceTree = ""; };
53 | "PasswordRules::PasswordRules::Product" /* PasswordRules.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = PasswordRules.framework; sourceTree = BUILT_PRODUCTS_DIR; };
54 | "PasswordRules::PasswordRulesTests::Product" /* PasswordRulesTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = PasswordRulesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
55 | /* End PBXFileReference section */
56 |
57 | /* Begin PBXFrameworksBuildPhase section */
58 | OBJ_23 /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 0;
61 | files = (
62 | );
63 | runOnlyForDeploymentPostprocessing = 0;
64 | };
65 | OBJ_42 /* Frameworks */ = {
66 | isa = PBXFrameworksBuildPhase;
67 | buildActionMask = 0;
68 | files = (
69 | OBJ_43 /* PasswordRules.framework in Frameworks */,
70 | );
71 | runOnlyForDeploymentPostprocessing = 0;
72 | };
73 | /* End PBXFrameworksBuildPhase section */
74 |
75 | /* Begin PBXGroup section */
76 | OBJ_10 /* Tests */ = {
77 | isa = PBXGroup;
78 | children = (
79 | OBJ_11 /* PasswordRulesTests */,
80 | );
81 | name = Tests;
82 | sourceTree = SOURCE_ROOT;
83 | };
84 | OBJ_11 /* PasswordRulesTests */ = {
85 | isa = PBXGroup;
86 | children = (
87 | OBJ_12 /* PasswordRulesTests.swift */,
88 | OBJ_13 /* XCTestManifests.swift */,
89 | );
90 | name = PasswordRulesTests;
91 | path = Tests/PasswordRulesTests;
92 | sourceTree = SOURCE_ROOT;
93 | };
94 | OBJ_14 /* Products */ = {
95 | isa = PBXGroup;
96 | children = (
97 | "PasswordRules::PasswordRulesTests::Product" /* PasswordRulesTests.xctest */,
98 | "PasswordRules::PasswordRules::Product" /* PasswordRules.framework */,
99 | );
100 | name = Products;
101 | sourceTree = BUILT_PRODUCTS_DIR;
102 | };
103 | OBJ_5 /* */ = {
104 | isa = PBXGroup;
105 | children = (
106 | OBJ_6 /* Package.swift */,
107 | OBJ_7 /* Sources */,
108 | OBJ_10 /* Tests */,
109 | OBJ_14 /* Products */,
110 | );
111 | name = "";
112 | sourceTree = "";
113 | };
114 | OBJ_7 /* Sources */ = {
115 | isa = PBXGroup;
116 | children = (
117 | OBJ_8 /* PasswordRules */,
118 | );
119 | name = Sources;
120 | sourceTree = SOURCE_ROOT;
121 | };
122 | OBJ_8 /* PasswordRules */ = {
123 | isa = PBXGroup;
124 | children = (
125 | OBJ_9 /* PasswordRules.swift */,
126 | );
127 | name = PasswordRules;
128 | path = Sources/PasswordRules;
129 | sourceTree = SOURCE_ROOT;
130 | };
131 | /* End PBXGroup section */
132 |
133 | /* Begin PBXNativeTarget section */
134 | "PasswordRules::PasswordRules" /* PasswordRules */ = {
135 | isa = PBXNativeTarget;
136 | buildConfigurationList = OBJ_18 /* Build configuration list for PBXNativeTarget "PasswordRules" */;
137 | buildPhases = (
138 | OBJ_21 /* Sources */,
139 | OBJ_23 /* Frameworks */,
140 | );
141 | buildRules = (
142 | );
143 | dependencies = (
144 | );
145 | name = PasswordRules;
146 | productName = PasswordRules;
147 | productReference = "PasswordRules::PasswordRules::Product" /* PasswordRules.framework */;
148 | productType = "com.apple.product-type.framework";
149 | };
150 | "PasswordRules::PasswordRulesTests" /* PasswordRulesTests */ = {
151 | isa = PBXNativeTarget;
152 | buildConfigurationList = OBJ_36 /* Build configuration list for PBXNativeTarget "PasswordRulesTests" */;
153 | buildPhases = (
154 | OBJ_39 /* Sources */,
155 | OBJ_42 /* Frameworks */,
156 | );
157 | buildRules = (
158 | );
159 | dependencies = (
160 | OBJ_44 /* PBXTargetDependency */,
161 | );
162 | name = PasswordRulesTests;
163 | productName = PasswordRulesTests;
164 | productReference = "PasswordRules::PasswordRulesTests::Product" /* PasswordRulesTests.xctest */;
165 | productType = "com.apple.product-type.bundle.unit-test";
166 | };
167 | "PasswordRules::SwiftPMPackageDescription" /* PasswordRulesPackageDescription */ = {
168 | isa = PBXNativeTarget;
169 | buildConfigurationList = OBJ_25 /* Build configuration list for PBXNativeTarget "PasswordRulesPackageDescription" */;
170 | buildPhases = (
171 | OBJ_28 /* Sources */,
172 | );
173 | buildRules = (
174 | );
175 | dependencies = (
176 | );
177 | name = PasswordRulesPackageDescription;
178 | productName = PasswordRulesPackageDescription;
179 | productType = "com.apple.product-type.framework";
180 | };
181 | /* End PBXNativeTarget section */
182 |
183 | /* Begin PBXProject section */
184 | OBJ_1 /* Project object */ = {
185 | isa = PBXProject;
186 | attributes = {
187 | LastUpgradeCheck = 9999;
188 | };
189 | buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "PasswordRules" */;
190 | compatibilityVersion = "Xcode 3.2";
191 | developmentRegion = English;
192 | hasScannedForEncodings = 0;
193 | knownRegions = (
194 | en,
195 | );
196 | mainGroup = OBJ_5 /* */;
197 | productRefGroup = OBJ_14 /* Products */;
198 | projectDirPath = "";
199 | projectRoot = "";
200 | targets = (
201 | "PasswordRules::PasswordRules" /* PasswordRules */,
202 | "PasswordRules::SwiftPMPackageDescription" /* PasswordRulesPackageDescription */,
203 | "PasswordRules::PasswordRulesPackageTests::ProductTarget" /* PasswordRulesPackageTests */,
204 | "PasswordRules::PasswordRulesTests" /* PasswordRulesTests */,
205 | );
206 | };
207 | /* End PBXProject section */
208 |
209 | /* Begin PBXSourcesBuildPhase section */
210 | OBJ_21 /* Sources */ = {
211 | isa = PBXSourcesBuildPhase;
212 | buildActionMask = 0;
213 | files = (
214 | OBJ_22 /* PasswordRules.swift in Sources */,
215 | );
216 | runOnlyForDeploymentPostprocessing = 0;
217 | };
218 | OBJ_28 /* Sources */ = {
219 | isa = PBXSourcesBuildPhase;
220 | buildActionMask = 0;
221 | files = (
222 | OBJ_29 /* Package.swift in Sources */,
223 | );
224 | runOnlyForDeploymentPostprocessing = 0;
225 | };
226 | OBJ_39 /* Sources */ = {
227 | isa = PBXSourcesBuildPhase;
228 | buildActionMask = 0;
229 | files = (
230 | OBJ_40 /* PasswordRulesTests.swift in Sources */,
231 | OBJ_41 /* XCTestManifests.swift in Sources */,
232 | );
233 | runOnlyForDeploymentPostprocessing = 0;
234 | };
235 | /* End PBXSourcesBuildPhase section */
236 |
237 | /* Begin PBXTargetDependency section */
238 | OBJ_34 /* PBXTargetDependency */ = {
239 | isa = PBXTargetDependency;
240 | target = "PasswordRules::PasswordRulesTests" /* PasswordRulesTests */;
241 | targetProxy = F8532BFE210F1AA400A3A56D /* PBXContainerItemProxy */;
242 | };
243 | OBJ_44 /* PBXTargetDependency */ = {
244 | isa = PBXTargetDependency;
245 | target = "PasswordRules::PasswordRules" /* PasswordRules */;
246 | targetProxy = F8532BFD210F1AA300A3A56D /* PBXContainerItemProxy */;
247 | };
248 | /* End PBXTargetDependency section */
249 |
250 | /* Begin XCBuildConfiguration section */
251 | OBJ_19 /* Debug */ = {
252 | isa = XCBuildConfiguration;
253 | buildSettings = {
254 | ENABLE_TESTABILITY = YES;
255 | FRAMEWORK_SEARCH_PATHS = (
256 | "$(inherited)",
257 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
258 | );
259 | HEADER_SEARCH_PATHS = "$(inherited)";
260 | INFOPLIST_FILE = PasswordRules.xcodeproj/PasswordRules_Info.plist;
261 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
262 | OTHER_CFLAGS = "$(inherited)";
263 | OTHER_LDFLAGS = "$(inherited)";
264 | OTHER_SWIFT_FLAGS = "$(inherited)";
265 | PRODUCT_BUNDLE_IDENTIFIER = PasswordRules;
266 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
267 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
268 | SKIP_INSTALL = YES;
269 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
270 | SWIFT_VERSION = 4.2;
271 | TARGET_NAME = PasswordRules;
272 | };
273 | name = Debug;
274 | };
275 | OBJ_20 /* Release */ = {
276 | isa = XCBuildConfiguration;
277 | buildSettings = {
278 | ENABLE_TESTABILITY = YES;
279 | FRAMEWORK_SEARCH_PATHS = (
280 | "$(inherited)",
281 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
282 | );
283 | HEADER_SEARCH_PATHS = "$(inherited)";
284 | INFOPLIST_FILE = PasswordRules.xcodeproj/PasswordRules_Info.plist;
285 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) $(TOOLCHAIN_DIR)/usr/lib/swift/macosx";
286 | OTHER_CFLAGS = "$(inherited)";
287 | OTHER_LDFLAGS = "$(inherited)";
288 | OTHER_SWIFT_FLAGS = "$(inherited)";
289 | PRODUCT_BUNDLE_IDENTIFIER = PasswordRules;
290 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
291 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
292 | SKIP_INSTALL = YES;
293 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
294 | SWIFT_VERSION = 4.2;
295 | TARGET_NAME = PasswordRules;
296 | };
297 | name = Release;
298 | };
299 | OBJ_26 /* Debug */ = {
300 | isa = XCBuildConfiguration;
301 | buildSettings = {
302 | LD = /usr/bin/true;
303 | OTHER_SWIFT_FLAGS = "-swift-version 4.2 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk";
304 | SWIFT_VERSION = 4.2;
305 | };
306 | name = Debug;
307 | };
308 | OBJ_27 /* Release */ = {
309 | isa = XCBuildConfiguration;
310 | buildSettings = {
311 | LD = /usr/bin/true;
312 | OTHER_SWIFT_FLAGS = "-swift-version 4.2 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk";
313 | SWIFT_VERSION = 4.2;
314 | };
315 | name = Release;
316 | };
317 | OBJ_3 /* Debug */ = {
318 | isa = XCBuildConfiguration;
319 | buildSettings = {
320 | CLANG_ENABLE_OBJC_ARC = YES;
321 | COMBINE_HIDPI_IMAGES = YES;
322 | COPY_PHASE_STRIP = NO;
323 | DEBUG_INFORMATION_FORMAT = dwarf;
324 | DYLIB_INSTALL_NAME_BASE = "@rpath";
325 | ENABLE_NS_ASSERTIONS = YES;
326 | GCC_OPTIMIZATION_LEVEL = 0;
327 | GCC_PREPROCESSOR_DEFINITIONS = (
328 | "DEBUG=1",
329 | "$(inherited)",
330 | );
331 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
332 | MACOSX_DEPLOYMENT_TARGET = 10.10;
333 | ONLY_ACTIVE_ARCH = YES;
334 | OTHER_SWIFT_FLAGS = "-DXcode";
335 | PRODUCT_NAME = "$(TARGET_NAME)";
336 | SDKROOT = iphoneos;
337 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
338 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "SWIFT_PACKAGE DEBUG";
339 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
340 | TVOS_DEPLOYMENT_TARGET = 10.0;
341 | USE_HEADERMAP = NO;
342 | WATCHOS_DEPLOYMENT_TARGET = 3.0;
343 | };
344 | name = Debug;
345 | };
346 | OBJ_32 /* Debug */ = {
347 | isa = XCBuildConfiguration;
348 | buildSettings = {
349 | };
350 | name = Debug;
351 | };
352 | OBJ_33 /* Release */ = {
353 | isa = XCBuildConfiguration;
354 | buildSettings = {
355 | };
356 | name = Release;
357 | };
358 | OBJ_37 /* Debug */ = {
359 | isa = XCBuildConfiguration;
360 | buildSettings = {
361 | CLANG_ENABLE_MODULES = YES;
362 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
363 | FRAMEWORK_SEARCH_PATHS = (
364 | "$(inherited)",
365 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
366 | );
367 | HEADER_SEARCH_PATHS = "$(inherited)";
368 | INFOPLIST_FILE = PasswordRules.xcodeproj/PasswordRulesTests_Info.plist;
369 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
370 | OTHER_CFLAGS = "$(inherited)";
371 | OTHER_LDFLAGS = "$(inherited)";
372 | OTHER_SWIFT_FLAGS = "$(inherited)";
373 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
374 | SWIFT_VERSION = 4.2;
375 | TARGET_NAME = PasswordRulesTests;
376 | };
377 | name = Debug;
378 | };
379 | OBJ_38 /* Release */ = {
380 | isa = XCBuildConfiguration;
381 | buildSettings = {
382 | CLANG_ENABLE_MODULES = YES;
383 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
384 | FRAMEWORK_SEARCH_PATHS = (
385 | "$(inherited)",
386 | "$(PLATFORM_DIR)/Developer/Library/Frameworks",
387 | );
388 | HEADER_SEARCH_PATHS = "$(inherited)";
389 | INFOPLIST_FILE = PasswordRules.xcodeproj/PasswordRulesTests_Info.plist;
390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks @loader_path/Frameworks";
391 | OTHER_CFLAGS = "$(inherited)";
392 | OTHER_LDFLAGS = "$(inherited)";
393 | OTHER_SWIFT_FLAGS = "$(inherited)";
394 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)";
395 | SWIFT_VERSION = 4.2;
396 | TARGET_NAME = PasswordRulesTests;
397 | };
398 | name = Release;
399 | };
400 | OBJ_4 /* Release */ = {
401 | isa = XCBuildConfiguration;
402 | buildSettings = {
403 | CLANG_ENABLE_OBJC_ARC = YES;
404 | COMBINE_HIDPI_IMAGES = YES;
405 | COPY_PHASE_STRIP = YES;
406 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
407 | DYLIB_INSTALL_NAME_BASE = "@rpath";
408 | GCC_OPTIMIZATION_LEVEL = s;
409 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
410 | MACOSX_DEPLOYMENT_TARGET = 10.10;
411 | OTHER_SWIFT_FLAGS = "-DXcode";
412 | PRODUCT_NAME = "$(TARGET_NAME)";
413 | SDKROOT = iphoneos;
414 | SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
415 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE;
416 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
417 | TVOS_DEPLOYMENT_TARGET = 10.0;
418 | USE_HEADERMAP = NO;
419 | WATCHOS_DEPLOYMENT_TARGET = 3.0;
420 | };
421 | name = Release;
422 | };
423 | /* End XCBuildConfiguration section */
424 |
425 | /* Begin XCConfigurationList section */
426 | OBJ_18 /* Build configuration list for PBXNativeTarget "PasswordRules" */ = {
427 | isa = XCConfigurationList;
428 | buildConfigurations = (
429 | OBJ_19 /* Debug */,
430 | OBJ_20 /* Release */,
431 | );
432 | defaultConfigurationIsVisible = 0;
433 | defaultConfigurationName = Release;
434 | };
435 | OBJ_2 /* Build configuration list for PBXProject "PasswordRules" */ = {
436 | isa = XCConfigurationList;
437 | buildConfigurations = (
438 | OBJ_3 /* Debug */,
439 | OBJ_4 /* Release */,
440 | );
441 | defaultConfigurationIsVisible = 0;
442 | defaultConfigurationName = Release;
443 | };
444 | OBJ_25 /* Build configuration list for PBXNativeTarget "PasswordRulesPackageDescription" */ = {
445 | isa = XCConfigurationList;
446 | buildConfigurations = (
447 | OBJ_26 /* Debug */,
448 | OBJ_27 /* Release */,
449 | );
450 | defaultConfigurationIsVisible = 0;
451 | defaultConfigurationName = Release;
452 | };
453 | OBJ_31 /* Build configuration list for PBXAggregateTarget "PasswordRulesPackageTests" */ = {
454 | isa = XCConfigurationList;
455 | buildConfigurations = (
456 | OBJ_32 /* Debug */,
457 | OBJ_33 /* Release */,
458 | );
459 | defaultConfigurationIsVisible = 0;
460 | defaultConfigurationName = Release;
461 | };
462 | OBJ_36 /* Build configuration list for PBXNativeTarget "PasswordRulesTests" */ = {
463 | isa = XCConfigurationList;
464 | buildConfigurations = (
465 | OBJ_37 /* Debug */,
466 | OBJ_38 /* Release */,
467 | );
468 | defaultConfigurationIsVisible = 0;
469 | defaultConfigurationName = Release;
470 | };
471 | /* End XCConfigurationList section */
472 | };
473 | rootObject = OBJ_1 /* Project object */;
474 | }
475 |
--------------------------------------------------------------------------------
/PasswordRules.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/PasswordRules.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PasswordRules.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PasswordRules.xcodeproj/xcshareddata/xcschemes/PasswordRules-Package.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
55 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
74 |
76 |
77 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PasswordRules
2 |
3 | A Swift library for defining strong password generator rules.
4 |
5 | This functionality is discussed in the NSHipster article
6 | [Password Rules / UITextInputPasswordRules](https://nshipster.com/uitextinputpasswordrules/).
7 |
8 | ---
9 |
10 | ## Requirements
11 |
12 | - Swift 4.0+
13 |
14 | ## Installation
15 |
16 | ### Swift Package Manager
17 |
18 | Add the PasswordRules package to your target dependencies in `Package.swift`:
19 |
20 | ```swift
21 | import PackageDescription
22 |
23 | let package = Package(
24 | name: "YourProject",
25 | dependencies: [
26 | .package(
27 | url: "https://github.com/NSHipster/PasswordRules",
28 | from: "1.0.0"
29 | ),
30 | ]
31 | )
32 | ```
33 |
34 | Then run the `swift build` command to build your project.
35 |
36 | ### Carthage
37 |
38 | To use PasswordRules in your Xcode project using Carthage,
39 | specify it in `Cartfile`:
40 |
41 | ```
42 | github "NSHipster/PasswordRules" ~> 1.0.0
43 | ```
44 |
45 | Then run the `carthage update` command to build the framework,
46 | and drag the built PasswordRules.framework into your Xcode project.
47 |
48 | ## Usage
49 |
50 | Define an array of `PasswordRules` cases
51 | and use the `descriptor(for:)` method to create a string representation:
52 |
53 | ```swift
54 | import PasswordRules
55 |
56 | let rules: [PasswordRule] = [ .required(.upper),
57 | .required(.lower),
58 | .required(.special),
59 | .minLength(20) ]
60 |
61 | let descriptor = PasswordRule.descriptor(for: rules)
62 | // "required: upper; required: lower; required: special; minlength: 20;"
63 | ```
64 |
65 | Initialize a `UITextInputPasswordRules` object using the descriptor
66 | and pass that to the `passwordRules` property of a secure text field:
67 |
68 | ```swift
69 | import UIKit
70 |
71 | guard #available(iOS 12, *) else {
72 | fatalError()
73 | }
74 |
75 | self.passwordTextField.passwordRules =
76 | UITextInputPasswordRules(descriptor: descriptor)
77 | ```
78 |
79 | ## License
80 |
81 | MIT
82 |
83 | ## Contact
84 |
85 | NSHipster ([@NSHipster](https://twitter.com/NSHipster))
86 |
--------------------------------------------------------------------------------
/Sources/PasswordRules/PasswordRules.swift:
--------------------------------------------------------------------------------
1 | public enum PasswordRule {
2 | public enum CharacterClass {
3 | case upper
4 | case lower
5 | case digits
6 | case special
7 | case asciiPrintable
8 | case unicode
9 | case custom(Set)
10 | }
11 |
12 | case required(CharacterClass)
13 | case allowed(CharacterClass)
14 | case maxConsecutive(UInt)
15 | case minLength(UInt)
16 | case maxLength(UInt)
17 |
18 | public static func descriptor(for rules: [PasswordRule]) -> String {
19 | return rules.map{ "\($0.description);" }.joined(separator: " ")
20 | }
21 | }
22 |
23 | extension PasswordRule: CustomStringConvertible {
24 | public var description: String {
25 | switch self {
26 | case .required(let characterClass):
27 | return "required: \(characterClass)"
28 | case .allowed(let characterClass):
29 | return "allowed: \(characterClass)"
30 | case .maxConsecutive(let length):
31 | return "max-consecutive: \(length)"
32 | case .minLength(let length):
33 | return "minlength: \(length)"
34 | case .maxLength(let length):
35 | return "maxlength: \(length)"
36 | }
37 | }
38 | }
39 |
40 | extension PasswordRule.CharacterClass: CustomStringConvertible {
41 | public var description: String {
42 | switch self {
43 | case .upper: return "upper"
44 | case .lower: return "lower"
45 | case .digits: return "digits"
46 | case .special: return "special"
47 | case .asciiPrintable: return "ascii-printable"
48 | case .unicode: return "unicode"
49 | case .custom(let characters):
50 | return "[" + String(characters) + "]"
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import PasswordRulesTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += PasswordRulesTests.allTests()
7 | XCTMain(tests)
--------------------------------------------------------------------------------
/Tests/PasswordRulesTests/PasswordRulesTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import PasswordRules
3 |
4 | final class PasswordRulesTests: XCTestCase {
5 | func testPasswordRules() {
6 | let rules: [PasswordRule] = [ .required(.upper),
7 | .required(.lower),
8 | .required(.special),
9 | .allowed(.asciiPrintable),
10 | .minLength(20) ]
11 |
12 | XCTAssertEqual(PasswordRule.descriptor(for: rules), "required: upper; required: lower; required: special; allowed: ascii-printable; minlength: 20;")
13 | }
14 |
15 | static var allTests = [
16 | ("testPasswordRules", testPasswordRules),
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/PasswordRulesTests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !os(macOS)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(PasswordRulesTests.allTests),
7 | ]
8 | }
9 | #endif
--------------------------------------------------------------------------------