Commit 854dd9d735
Unsigned
Layout: unified · split
Hutch.xcodeproj/project.pbxproj +130
| @@ -13,12 +13,25 @@ | ||
| 13 | 13 | 8B2F89682F69DEB900FC0253 /* SECURITY.md in Resources */ = {isa = PBXBuildFile; fileRef = 8B2F89652F69DEB900FC0253 /* SECURITY.md */; }; |
| 14 | 14 | /* End PBXBuildFile section */ |
| 15 | 15 | |
| 16 | /* Begin PBXContainerItemProxy section */ | |
| 17 | 8B8182BB2F6B73F3000AE049 /* PBXContainerItemProxy */ = { | |
| 18 | isa = PBXContainerItemProxy; | |
| 19 | containerPortal = 8B4B28C92F6704280045FA19 /* Project object */; | |
| 20 | proxyType = 1; | |
| 21 | remoteGlobalIDString = 8B4B28D02F6704280045FA19; | |
| 22 | remoteInfo = Hutch; | |
| 23 | }; | |
| 24 | /* End PBXContainerItemProxy section */ | |
| 25 | ||
| 16 | 26 | /* Begin PBXFileReference section */ |
| 17 | 27 | 8B2F89612F69DEA900FC0253 /* TODO.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = TODO.md; sourceTree = "<group>"; }; |
| 18 | 28 | 8B2F89632F69DEB900FC0253 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; }; |
| 19 | 29 | 8B2F89642F69DEB900FC0253 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; }; |
| 20 | 30 | 8B2F89652F69DEB900FC0253 /* SECURITY.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = SECURITY.md; sourceTree = "<group>"; }; |
| 21 | 31 | 8B4B28D12F6704280045FA19 /* Hutch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Hutch.app; sourceTree = BUILT_PRODUCTS_DIR; }; |
| 32 | 8B8182B72F6B73F3000AE049 /* HutchTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HutchTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | |
| 33 | 8B8182C22F6B742B000AE049 /* HutchTests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = HutchTests; sourceTree = "<group>"; }; | |
| 34 | 8BDCA5272F6B76B20066AA29 /* HutchTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = HutchTests.xctestplan; sourceTree = "<group>"; }; | |
| 22 | 35 | /* End PBXFileReference section */ |
| 23 | 36 | |
| 24 | 37 | /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ |
| @@ -40,6 +53,11 @@ | ||
| 40 | 53 | path = Hutch; |
| 41 | 54 | sourceTree = "<group>"; |
| 42 | 55 | }; |
| 56 | 8B8182B82F6B73F3000AE049 /* HutchTests */ = { | |
| 57 | isa = PBXFileSystemSynchronizedRootGroup; | |
| 58 | path = HutchTests; | |
| 59 | sourceTree = "<group>"; | |
| 60 | }; | |
| 43 | 61 | /* End PBXFileSystemSynchronizedRootGroup section */ |
| 44 | 62 | |
| 45 | 63 | /* Begin PBXFrameworksBuildPhase section */ |
| @@ -50,17 +68,27 @@ | ||
| 50 | 68 | ); |
| 51 | 69 | runOnlyForDeploymentPostprocessing = 0; |
| 52 | 70 | }; |
| 71 | 8B8182B42F6B73F3000AE049 /* Frameworks */ = { | |
| 72 | isa = PBXFrameworksBuildPhase; | |
| 73 | buildActionMask = 2147483647; | |
| 74 | files = ( | |
| 75 | ); | |
| 76 | runOnlyForDeploymentPostprocessing = 0; | |
| 77 | }; | |
| 53 | 78 | /* End PBXFrameworksBuildPhase section */ |
| 54 | 79 | |
| 55 | 80 | /* Begin PBXGroup section */ |
| 56 | 81 | 8B4B28C82F6704280045FA19 = { |
| 57 | 82 | isa = PBXGroup; |
| 58 | 83 | children = ( |
| 84 | 8BDCA5272F6B76B20066AA29 /* HutchTests.xctestplan */, | |
| 85 | 8B8182C22F6B742B000AE049 /* HutchTests */, | |
| 59 | 86 | 8B2F89632F69DEB900FC0253 /* LICENSE */, |
| 60 | 87 | 8B2F89642F69DEB900FC0253 /* README.md */, |
| 61 | 88 | 8B2F89652F69DEB900FC0253 /* SECURITY.md */, |
| 62 | 89 | 8B2F89612F69DEA900FC0253 /* TODO.md */, |
| 63 | 90 | 8B4B28D32F6704280045FA19 /* Hutch */, |
| 91 | 8B8182B82F6B73F3000AE049 /* HutchTests */, | |
| 64 | 92 | 8B4B28D22F6704280045FA19 /* Products */, |
| 65 | 93 | ); |
| 66 | 94 | sourceTree = "<group>"; |
| @@ -69,6 +97,7 @@ | ||
| 69 | 97 | isa = PBXGroup; |
| 70 | 98 | children = ( |
| 71 | 99 | 8B4B28D12F6704280045FA19 /* Hutch.app */, |
| 100 | 8B8182B72F6B73F3000AE049 /* HutchTests.xctest */, | |
| 72 | 101 | ); |
| 73 | 102 | name = Products; |
| 74 | 103 | sourceTree = "<group>"; |
| @@ -98,6 +127,29 @@ | ||
| 98 | 127 | productReference = 8B4B28D12F6704280045FA19 /* Hutch.app */; |
| 99 | 128 | productType = "com.apple.product-type.application"; |
| 100 | 129 | }; |
| 130 | 8B8182B62F6B73F3000AE049 /* HutchTests */ = { | |
| 131 | isa = PBXNativeTarget; | |
| 132 | buildConfigurationList = 8B8182BF2F6B73F3000AE049 /* Build configuration list for PBXNativeTarget "HutchTests" */; | |
| 133 | buildPhases = ( | |
| 134 | 8B8182B32F6B73F3000AE049 /* Sources */, | |
| 135 | 8B8182B42F6B73F3000AE049 /* Frameworks */, | |
| 136 | 8B8182B52F6B73F3000AE049 /* Resources */, | |
| 137 | ); | |
| 138 | buildRules = ( | |
| 139 | ); | |
| 140 | dependencies = ( | |
| 141 | 8B8182BC2F6B73F3000AE049 /* PBXTargetDependency */, | |
| 142 | ); | |
| 143 | fileSystemSynchronizedGroups = ( | |
| 144 | 8B8182B82F6B73F3000AE049 /* HutchTests */, | |
| 145 | ); | |
| 146 | name = HutchTests; | |
| 147 | packageProductDependencies = ( | |
| 148 | ); | |
| 149 | productName = HutchTests; | |
| 150 | productReference = 8B8182B72F6B73F3000AE049 /* HutchTests.xctest */; | |
| 151 | productType = "com.apple.product-type.bundle.unit-test"; | |
| 152 | }; | |
| 101 | 153 | /* End PBXNativeTarget section */ |
| 102 | 154 | |
| 103 | 155 | /* Begin PBXProject section */ |
| @@ -111,6 +163,10 @@ | ||
| 111 | 163 | 8B4B28D02F6704280045FA19 = { |
| 112 | 164 | CreatedOnToolsVersion = 26.3; |
| 113 | 165 | }; |
| 166 | 8B8182B62F6B73F3000AE049 = { | |
| 167 | CreatedOnToolsVersion = 26.3; | |
| 168 | TestTargetID = 8B4B28D02F6704280045FA19; | |
| 169 | }; | |
| 114 | 170 | }; |
| 115 | 171 | }; |
| 116 | 172 | buildConfigurationList = 8B4B28CC2F6704280045FA19 /* Build configuration list for PBXProject "Hutch" */; |
| @@ -128,6 +184,7 @@ | ||
| 128 | 184 | projectRoot = ""; |
| 129 | 185 | targets = ( |
| 130 | 186 | 8B4B28D02F6704280045FA19 /* Hutch */, |
| 187 | 8B8182B62F6B73F3000AE049 /* HutchTests */, | |
| 131 | 188 | ); |
| 132 | 189 | }; |
| 133 | 190 | /* End PBXProject section */ |
| @@ -144,6 +201,13 @@ | ||
| 144 | 201 | ); |
| 145 | 202 | runOnlyForDeploymentPostprocessing = 0; |
| 146 | 203 | }; |
| 204 | 8B8182B52F6B73F3000AE049 /* Resources */ = { | |
| 205 | isa = PBXResourcesBuildPhase; | |
| 206 | buildActionMask = 2147483647; | |
| 207 | files = ( | |
| 208 | ); | |
| 209 | runOnlyForDeploymentPostprocessing = 0; | |
| 210 | }; | |
| 147 | 211 | /* End PBXResourcesBuildPhase section */ |
| 148 | 212 | |
| 149 | 213 | /* Begin PBXSourcesBuildPhase section */ |
| @@ -154,8 +218,23 @@ | ||
| 154 | 218 | ); |
| 155 | 219 | runOnlyForDeploymentPostprocessing = 0; |
| 156 | 220 | }; |
| 221 | 8B8182B32F6B73F3000AE049 /* Sources */ = { | |
| 222 | isa = PBXSourcesBuildPhase; | |
| 223 | buildActionMask = 2147483647; | |
| 224 | files = ( | |
| 225 | ); | |
| 226 | runOnlyForDeploymentPostprocessing = 0; | |
| 227 | }; | |
| 157 | 228 | /* End PBXSourcesBuildPhase section */ |
| 158 | 229 | |
| 230 | /* Begin PBXTargetDependency section */ | |
| 231 | 8B8182BC2F6B73F3000AE049 /* PBXTargetDependency */ = { | |
| 232 | isa = PBXTargetDependency; | |
| 233 | target = 8B4B28D02F6704280045FA19 /* Hutch */; | |
| 234 | targetProxy = 8B8182BB2F6B73F3000AE049 /* PBXContainerItemProxy */; | |
| 235 | }; | |
| 236 | /* End PBXTargetDependency section */ | |
| 237 | ||
| 159 | 238 | /* Begin XCBuildConfiguration section */ |
| 160 | 239 | 8B4B28DA2F6704290045FA19 /* Debug */ = { |
| 161 | 240 | isa = XCBuildConfiguration; |
| @@ -350,6 +429,48 @@ | ||
| 350 | 429 | }; |
| 351 | 430 | name = Release; |
| 352 | 431 | }; |
| 432 | 8B8182BD2F6B73F3000AE049 /* Debug */ = { | |
| 433 | isa = XCBuildConfiguration; | |
| 434 | buildSettings = { | |
| 435 | BUNDLE_LOADER = "$(TEST_HOST)"; | |
| 436 | CODE_SIGN_STYLE = Automatic; | |
| 437 | CURRENT_PROJECT_VERSION = 1; | |
| 438 | DEVELOPMENT_TEAM = ZCNAX3VL9D; | |
| 439 | GENERATE_INFOPLIST_FILE = YES; | |
| 440 | MARKETING_VERSION = 1.0; | |
| 441 | PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.HutchTests; | |
| 442 | PRODUCT_NAME = "$(TARGET_NAME)"; | |
| 443 | STRING_CATALOG_GENERATE_SYMBOLS = NO; | |
| 444 | SWIFT_APPROACHABLE_CONCURRENCY = YES; | |
| 445 | SWIFT_EMIT_LOC_STRINGS = NO; | |
| 446 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; | |
| 447 | SWIFT_VERSION = 5.0; | |
| 448 | TARGETED_DEVICE_FAMILY = "1,2"; | |
| 449 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Hutch.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Hutch"; | |
| 450 | }; | |
| 451 | name = Debug; | |
| 452 | }; | |
| 453 | 8B8182BE2F6B73F3000AE049 /* Release */ = { | |
| 454 | isa = XCBuildConfiguration; | |
| 455 | buildSettings = { | |
| 456 | BUNDLE_LOADER = "$(TEST_HOST)"; | |
| 457 | CODE_SIGN_STYLE = Automatic; | |
| 458 | CURRENT_PROJECT_VERSION = 1; | |
| 459 | DEVELOPMENT_TEAM = ZCNAX3VL9D; | |
| 460 | GENERATE_INFOPLIST_FILE = YES; | |
| 461 | MARKETING_VERSION = 1.0; | |
| 462 | PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.HutchTests; | |
| 463 | PRODUCT_NAME = "$(TARGET_NAME)"; | |
| 464 | STRING_CATALOG_GENERATE_SYMBOLS = NO; | |
| 465 | SWIFT_APPROACHABLE_CONCURRENCY = YES; | |
| 466 | SWIFT_EMIT_LOC_STRINGS = NO; | |
| 467 | SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; | |
| 468 | SWIFT_VERSION = 5.0; | |
| 469 | TARGETED_DEVICE_FAMILY = "1,2"; | |
| 470 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Hutch.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Hutch"; | |
| 471 | }; | |
| 472 | name = Release; | |
| 473 | }; | |
| 353 | 474 | /* End XCBuildConfiguration section */ |
| 354 | 475 | |
| 355 | 476 | /* Begin XCConfigurationList section */ |
| @@ -371,6 +492,15 @@ | ||
| 371 | 492 | defaultConfigurationIsVisible = 0; |
| 372 | 493 | defaultConfigurationName = Release; |
| 373 | 494 | }; |
| 495 | 8B8182BF2F6B73F3000AE049 /* Build configuration list for PBXNativeTarget "HutchTests" */ = { | |
| 496 | isa = XCConfigurationList; | |
| 497 | buildConfigurations = ( | |
| 498 | 8B8182BD2F6B73F3000AE049 /* Debug */, | |
| 499 | 8B8182BE2F6B73F3000AE049 /* Release */, | |
| 500 | ); | |
| 501 | defaultConfigurationIsVisible = 0; | |
| 502 | defaultConfigurationName = Release; | |
| 503 | }; | |
| 374 | 504 | /* End XCConfigurationList section */ |
| 375 | 505 | }; |
| 376 | 506 | rootObject = 8B4B28C92F6704280045FA19 /* Project object */; |
Hutch.xcodeproj/xcshareddata/xcschemes/Hutch.xcscheme added +96
| @@ -0,0 +1,96 @@ | ||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <Scheme | |
| 3 | LastUpgradeVersion = "2630" | |
| 4 | version = "1.7"> | |
| 5 | <BuildAction | |
| 6 | parallelizeBuildables = "YES" | |
| 7 | buildImplicitDependencies = "YES" | |
| 8 | buildArchitectures = "Automatic"> | |
| 9 | <BuildActionEntries> | |
| 10 | <BuildActionEntry | |
| 11 | buildForTesting = "YES" | |
| 12 | buildForRunning = "YES" | |
| 13 | buildForProfiling = "YES" | |
| 14 | buildForArchiving = "YES" | |
| 15 | buildForAnalyzing = "YES"> | |
| 16 | <BuildableReference | |
| 17 | BuildableIdentifier = "primary" | |
| 18 | BlueprintIdentifier = "8B4B28D02F6704280045FA19" | |
| 19 | BuildableName = "Hutch.app" | |
| 20 | BlueprintName = "Hutch" | |
| 21 | ReferencedContainer = "container:Hutch.xcodeproj"> | |
| 22 | </BuildableReference> | |
| 23 | </BuildActionEntry> | |
| 24 | </BuildActionEntries> | |
| 25 | </BuildAction> | |
| 26 | <TestAction | |
| 27 | buildConfiguration = "Debug" | |
| 28 | selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |
| 29 | selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |
| 30 | shouldUseLaunchSchemeArgsEnv = "YES"> | |
| 31 | <TestPlans> | |
| 32 | <TestPlanReference | |
| 33 | reference = "container:HutchTests" | |
| 34 | default = "YES"> | |
| 35 | </TestPlanReference> | |
| 36 | </TestPlans> | |
| 37 | <Testables> | |
| 38 | <TestableReference | |
| 39 | skipped = "NO" | |
| 40 | parallelizable = "YES"> | |
| 41 | <BuildableReference | |
| 42 | BuildableIdentifier = "primary" | |
| 43 | BlueprintIdentifier = "8B8182B62F6B73F3000AE049" | |
| 44 | BuildableName = "HutchTests.xctest" | |
| 45 | BlueprintName = "HutchTests" | |
| 46 | ReferencedContainer = "container:Hutch.xcodeproj"> | |
| 47 | </BuildableReference> | |
| 48 | </TestableReference> | |
| 49 | </Testables> | |
| 50 | </TestAction> | |
| 51 | <LaunchAction | |
| 52 | buildConfiguration = "Debug" | |
| 53 | selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |
| 54 | selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |
| 55 | launchStyle = "0" | |
| 56 | useCustomWorkingDirectory = "NO" | |
| 57 | ignoresPersistentStateOnLaunch = "NO" | |
| 58 | debugDocumentVersioning = "YES" | |
| 59 | debugServiceExtension = "internal" | |
| 60 | allowLocationSimulation = "YES"> | |
| 61 | <BuildableProductRunnable | |
| 62 | runnableDebuggingMode = "0"> | |
| 63 | <BuildableReference | |
| 64 | BuildableIdentifier = "primary" | |
| 65 | BlueprintIdentifier = "8B4B28D02F6704280045FA19" | |
| 66 | BuildableName = "Hutch.app" | |
| 67 | BlueprintName = "Hutch" | |
| 68 | ReferencedContainer = "container:Hutch.xcodeproj"> | |
| 69 | </BuildableReference> | |
| 70 | </BuildableProductRunnable> | |
| 71 | </LaunchAction> | |
| 72 | <ProfileAction | |
| 73 | buildConfiguration = "Release" | |
| 74 | shouldUseLaunchSchemeArgsEnv = "YES" | |
| 75 | savedToolIdentifier = "" | |
| 76 | useCustomWorkingDirectory = "NO" | |
| 77 | debugDocumentVersioning = "YES"> | |
| 78 | <BuildableProductRunnable | |
| 79 | runnableDebuggingMode = "0"> | |
| 80 | <BuildableReference | |
| 81 | BuildableIdentifier = "primary" | |
| 82 | BlueprintIdentifier = "8B4B28D02F6704280045FA19" | |
| 83 | BuildableName = "Hutch.app" | |
| 84 | BlueprintName = "Hutch" | |
| 85 | ReferencedContainer = "container:Hutch.xcodeproj"> | |
| 86 | </BuildableReference> | |
| 87 | </BuildableProductRunnable> | |
| 88 | </ProfileAction> | |
| 89 | <AnalyzeAction | |
| 90 | buildConfiguration = "Debug"> | |
| 91 | </AnalyzeAction> | |
| 92 | <ArchiveAction | |
| 93 | buildConfiguration = "Release" | |
| 94 | revealArchiveInOrganizer = "YES"> | |
| 95 | </ArchiveAction> | |
| 96 | </Scheme> | |
Hutch.xcodeproj/xcshareddata/xcschemes/HutchTests.xcscheme added +69
| @@ -0,0 +1,69 @@ | ||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | |
| 2 | <Scheme | |
| 3 | LastUpgradeVersion = "2630" | |
| 4 | version = "1.7"> | |
| 5 | <BuildAction | |
| 6 | parallelizeBuildables = "YES" | |
| 7 | buildImplicitDependencies = "YES" | |
| 8 | buildArchitectures = "Automatic"> | |
| 9 | </BuildAction> | |
| 10 | <TestAction | |
| 11 | buildConfiguration = "Debug" | |
| 12 | selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |
| 13 | selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |
| 14 | shouldUseLaunchSchemeArgsEnv = "YES"> | |
| 15 | <TestPlans> | |
| 16 | <TestPlanReference | |
| 17 | reference = "container:HutchTests.xctestplan" | |
| 18 | default = "YES"> | |
| 19 | </TestPlanReference> | |
| 20 | </TestPlans> | |
| 21 | <Testables> | |
| 22 | <TestableReference | |
| 23 | skipped = "NO" | |
| 24 | parallelizable = "YES"> | |
| 25 | <BuildableReference | |
| 26 | BuildableIdentifier = "primary" | |
| 27 | BlueprintIdentifier = "8B8182B62F6B73F3000AE049" | |
| 28 | BuildableName = "HutchTests.xctest" | |
| 29 | BlueprintName = "HutchTests" | |
| 30 | ReferencedContainer = "container:Hutch.xcodeproj"> | |
| 31 | </BuildableReference> | |
| 32 | </TestableReference> | |
| 33 | </Testables> | |
| 34 | </TestAction> | |
| 35 | <LaunchAction | |
| 36 | buildConfiguration = "Debug" | |
| 37 | selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |
| 38 | selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |
| 39 | launchStyle = "0" | |
| 40 | useCustomWorkingDirectory = "NO" | |
| 41 | ignoresPersistentStateOnLaunch = "NO" | |
| 42 | debugDocumentVersioning = "YES" | |
| 43 | debugServiceExtension = "internal" | |
| 44 | allowLocationSimulation = "YES"> | |
| 45 | <MacroExpansion> | |
| 46 | <BuildableReference | |
| 47 | BuildableIdentifier = "primary" | |
| 48 | BlueprintIdentifier = "8B4B28D02F6704280045FA19" | |
| 49 | BuildableName = "Hutch.app" | |
| 50 | BlueprintName = "Hutch" | |
| 51 | ReferencedContainer = "container:Hutch.xcodeproj"> | |
| 52 | </BuildableReference> | |
| 53 | </MacroExpansion> | |
| 54 | </LaunchAction> | |
| 55 | <ProfileAction | |
| 56 | buildConfiguration = "Release" | |
| 57 | shouldUseLaunchSchemeArgsEnv = "YES" | |
| 58 | savedToolIdentifier = "" | |
| 59 | useCustomWorkingDirectory = "NO" | |
| 60 | debugDocumentVersioning = "YES"> | |
| 61 | </ProfileAction> | |
| 62 | <AnalyzeAction | |
| 63 | buildConfiguration = "Debug"> | |
| 64 | </AnalyzeAction> | |
| 65 | <ArchiveAction | |
| 66 | buildConfiguration = "Release" | |
| 67 | revealArchiveInOrganizer = "YES"> | |
| 68 | </ArchiveAction> | |
| 69 | </Scheme> | |
Hutch/Networking/SRHTClient.swift +14
| @@ -435,6 +435,9 @@ final class SRHTClient: Sendable { | ||
| 435 | 435 | guard let token = _token.withLock({ $0 }), !token.isEmpty else { |
| 436 | 436 | throw SRHTError.unauthorized |
| 437 | 437 | } |
| 438 | guard Self.isTrustedAuthenticatedTextURL(url) else { | |
| 439 | throw SRHTError.invalidAuthenticatedURL(url) | |
| 440 | } | |
| 438 | 441 | |
| 439 | 442 | var request = URLRequest(url: url) |
| 440 | 443 | request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") |
| @@ -512,6 +515,17 @@ final class SRHTClient: Sendable { | ||
| 512 | 515 | |
| 513 | 516 | // MARK: - Data Helper |
| 514 | 517 | |
| 518 | private extension SRHTClient { | |
| 519 | static func isTrustedAuthenticatedTextURL(_ url: URL) -> Bool { | |
| 520 | guard url.scheme?.localizedCaseInsensitiveCompare("https") == .orderedSame, | |
| 521 | let host = url.host?.lowercased() else { | |
| 522 | return false | |
| 523 | } | |
| 524 | ||
| 525 | return host.hasSuffix(".sr.ht") | |
| 526 | } | |
| 527 | } | |
| 528 | ||
| 515 | 529 | private extension Data { |
| 516 | 530 | mutating func append(_ string: String) { |
| 517 | 531 | if let data = string.data(using: .utf8) { |
Hutch/Networking/SRHTError.swift +4
| @@ -6,6 +6,8 @@ enum SRHTError: LocalizedError, Sendable { | ||
| 6 | 6 | case graphQLErrors([GraphQLError]) |
| 7 | 7 | /// The HTTP response had a non-2xx status code. |
| 8 | 8 | case httpError(Int) |
| 9 | /// The client refused to send credentials to an unexpected URL. | |
| 10 | case invalidAuthenticatedURL(URL) | |
| 9 | 11 | /// The response data could not be decoded. |
| 10 | 12 | case decodingError(any Error) |
| 11 | 13 | /// A networking error from URLSession (timeout, DNS, connectivity, etc.). |
| @@ -20,6 +22,8 @@ enum SRHTError: LocalizedError, Sendable { | ||
| 20 | 22 | return "GraphQL error: \(messages)" |
| 21 | 23 | case .httpError(let code): |
| 22 | 24 | return "Server returned HTTP \(code)." |
| 25 | case .invalidAuthenticatedURL(let url): | |
| 26 | return "Refused to authenticate request to unexpected URL: \(url.absoluteString)" | |
| 23 | 27 | case .decodingError(let error): |
| 24 | 28 | return "Failed to decode response: \(error.localizedDescription)" |
| 25 | 29 | case .networkError(let error): |
HutchTests.xctestplan added +30
| @@ -0,0 +1,30 @@ | ||
| 1 | { | |
| 2 | "configurations" : [ | |
| 3 | { | |
| 4 | "id" : "06A589A5-80C7-41FE-911F-03518252CBDD", | |
| 5 | "name" : "Test Scheme Action", | |
| 6 | "options" : { | |
| 7 | ||
| 8 | } | |
| 9 | } | |
| 10 | ], | |
| 11 | "defaultOptions" : { | |
| 12 | "performanceAntipatternCheckerEnabled" : true, | |
| 13 | "targetForVariableExpansion" : { | |
| 14 | "containerPath" : "container:Hutch.xcodeproj", | |
| 15 | "identifier" : "8B4B28D02F6704280045FA19", | |
| 16 | "name" : "Hutch" | |
| 17 | } | |
| 18 | }, | |
| 19 | "testTargets" : [ | |
| 20 | { | |
| 21 | "parallelizable" : true, | |
| 22 | "target" : { | |
| 23 | "containerPath" : "container:Hutch.xcodeproj", | |
| 24 | "identifier" : "8B8182B62F6B73F3000AE049", | |
| 25 | "name" : "HutchTests" | |
| 26 | } | |
| 27 | } | |
| 28 | ], | |
| 29 | "version" : 1 | |
| 30 | } | |
HutchTests/HutchTests.swift added +16
| @@ -0,0 +1,16 @@ | ||
| 1 | // | |
| 2 | // HutchTests.swift | |
| 3 | // HutchTests | |
| 4 | // | |
| 5 | // Created by cmc on 2026-03-18. | |
| 6 | // | |
| 7 | ||
| 8 | import Testing | |
| 9 | ||
| 10 | struct HutchTests { | |
| 11 | ||
| 12 | @Test func example() async throws { | |
| 13 | // Write your test here and use APIs like `#expect(...)` to check expected conditions. | |
| 14 | } | |
| 15 | ||
| 16 | } | |
HutchTests/SRHTClientTests.swift added +27
| @@ -0,0 +1,27 @@ | ||
| 1 | import Foundation | |
| 2 | import Testing | |
| 3 | @testable import Hutch | |
| 4 | ||
| 5 | struct SRHTClientTests { | |
| 6 | ||
| 7 | @Test | |
| 8 | @MainActor | |
| 9 | func fetchTextRejectsUnexpectedAuthenticatedURL() async throws { | |
| 10 | let client = SRHTClient(token: "test-token") | |
| 11 | let url = try #require(URL(string: "https://example.com/build-log")) | |
| 12 | ||
| 13 | do { | |
| 14 | _ = try await client.fetchText(url: url) | |
| 15 | Issue.record("Expected fetchText(url:) to reject non-sr.ht URLs.") | |
| 16 | } catch let error as SRHTError { | |
| 17 | guard case .invalidAuthenticatedURL(let rejectedURL) = error else { | |
| 18 | Issue.record("Expected invalidAuthenticatedURL error, got \(error).") | |
| 19 | return | |
| 20 | } | |
| 21 | ||
| 22 | #expect(rejectedURL == url) | |
| 23 | } catch { | |
| 24 | Issue.record("Expected SRHTError.invalidAuthenticatedURL, got \(error).") | |
| 25 | } | |
| 26 | } | |
| 27 | } | |