├── LICENSE ├── README.md ├── share-mount.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── kmeziere02.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist └── share-mount ├── Assets.xcassets ├── AccentColor.colorset │ └── Contents.json ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── ContentView.swift ├── Preview Content └── Preview Assets.xcassets │ └── Contents.json ├── mounts └── MountsView.swift ├── share_mount.entitlements ├── share_mountApp.swift ├── statusMenu.swift └── ts_mount.swift /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 John Paul Catholic University 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # share-mount 2 | A simple app that looks for tailscale peers with tags containing "smb." Mounts as guest on default port. 3 | 4 | -------------------------------------------------------------------------------- /share-mount.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 622706182A20065600402F49 /* share_mountApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 622706172A20065600402F49 /* share_mountApp.swift */; }; 11 | 6227061A2A20065600402F49 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 622706192A20065600402F49 /* ContentView.swift */; }; 12 | 6227061C2A20065700402F49 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6227061B2A20065700402F49 /* Assets.xcassets */; }; 13 | 6227061F2A20065700402F49 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6227061E2A20065700402F49 /* Preview Assets.xcassets */; }; 14 | 622706272A2009B200402F49 /* statusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 622706262A2009B200402F49 /* statusMenu.swift */; }; 15 | 6227062A2A200A0600402F49 /* MountsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 622706292A200A0600402F49 /* MountsView.swift */; }; 16 | 6227062C2A200A2400402F49 /* ts_mount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6227062B2A200A2400402F49 /* ts_mount.swift */; }; 17 | 6227062E2A200C3300402F49 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 6227062D2A200C3300402F49 /* LICENSE */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 622706142A20065600402F49 /* share-mount.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "share-mount.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | 622706172A20065600402F49 /* share_mountApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = share_mountApp.swift; sourceTree = ""; }; 23 | 622706192A20065600402F49 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 24 | 6227061B2A20065700402F49 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | 6227061E2A20065700402F49 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 26 | 622706202A20065700402F49 /* share_mount.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = share_mount.entitlements; sourceTree = ""; }; 27 | 622706262A2009B200402F49 /* statusMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = statusMenu.swift; sourceTree = ""; }; 28 | 622706292A200A0600402F49 /* MountsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MountsView.swift; sourceTree = ""; }; 29 | 6227062B2A200A2400402F49 /* ts_mount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ts_mount.swift; sourceTree = ""; }; 30 | 6227062D2A200C3300402F49 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 31 | 6227062F2A200C5F00402F49 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 32 | /* End PBXFileReference section */ 33 | 34 | /* Begin PBXFrameworksBuildPhase section */ 35 | 622706112A20065600402F49 /* Frameworks */ = { 36 | isa = PBXFrameworksBuildPhase; 37 | buildActionMask = 2147483647; 38 | files = ( 39 | ); 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXFrameworksBuildPhase section */ 43 | 44 | /* Begin PBXGroup section */ 45 | 6227060B2A20065600402F49 = { 46 | isa = PBXGroup; 47 | children = ( 48 | 6227062F2A200C5F00402F49 /* README.md */, 49 | 6227062D2A200C3300402F49 /* LICENSE */, 50 | 622706162A20065600402F49 /* share-mount */, 51 | 622706152A20065600402F49 /* Products */, 52 | ); 53 | sourceTree = ""; 54 | }; 55 | 622706152A20065600402F49 /* Products */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | 622706142A20065600402F49 /* share-mount.app */, 59 | ); 60 | name = Products; 61 | sourceTree = ""; 62 | }; 63 | 622706162A20065600402F49 /* share-mount */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 622706282A2009EF00402F49 /* mounts */, 67 | 622706262A2009B200402F49 /* statusMenu.swift */, 68 | 622706172A20065600402F49 /* share_mountApp.swift */, 69 | 622706192A20065600402F49 /* ContentView.swift */, 70 | 6227061B2A20065700402F49 /* Assets.xcassets */, 71 | 622706202A20065700402F49 /* share_mount.entitlements */, 72 | 6227061D2A20065700402F49 /* Preview Content */, 73 | 6227062B2A200A2400402F49 /* ts_mount.swift */, 74 | ); 75 | path = "share-mount"; 76 | sourceTree = ""; 77 | }; 78 | 6227061D2A20065700402F49 /* Preview Content */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 6227061E2A20065700402F49 /* Preview Assets.xcassets */, 82 | ); 83 | path = "Preview Content"; 84 | sourceTree = ""; 85 | }; 86 | 622706282A2009EF00402F49 /* mounts */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 622706292A200A0600402F49 /* MountsView.swift */, 90 | ); 91 | path = mounts; 92 | sourceTree = ""; 93 | }; 94 | /* End PBXGroup section */ 95 | 96 | /* Begin PBXNativeTarget section */ 97 | 622706132A20065600402F49 /* share-mount */ = { 98 | isa = PBXNativeTarget; 99 | buildConfigurationList = 622706232A20065700402F49 /* Build configuration list for PBXNativeTarget "share-mount" */; 100 | buildPhases = ( 101 | 622706102A20065600402F49 /* Sources */, 102 | 622706112A20065600402F49 /* Frameworks */, 103 | 622706122A20065600402F49 /* Resources */, 104 | ); 105 | buildRules = ( 106 | ); 107 | dependencies = ( 108 | ); 109 | name = "share-mount"; 110 | productName = "share-mount"; 111 | productReference = 622706142A20065600402F49 /* share-mount.app */; 112 | productType = "com.apple.product-type.application"; 113 | }; 114 | /* End PBXNativeTarget section */ 115 | 116 | /* Begin PBXProject section */ 117 | 6227060C2A20065600402F49 /* Project object */ = { 118 | isa = PBXProject; 119 | attributes = { 120 | BuildIndependentTargetsInParallel = 1; 121 | LastSwiftUpdateCheck = 1430; 122 | LastUpgradeCheck = 1430; 123 | TargetAttributes = { 124 | 622706132A20065600402F49 = { 125 | CreatedOnToolsVersion = 14.3; 126 | }; 127 | }; 128 | }; 129 | buildConfigurationList = 6227060F2A20065600402F49 /* Build configuration list for PBXProject "share-mount" */; 130 | compatibilityVersion = "Xcode 14.0"; 131 | developmentRegion = en; 132 | hasScannedForEncodings = 0; 133 | knownRegions = ( 134 | en, 135 | Base, 136 | ); 137 | mainGroup = 6227060B2A20065600402F49; 138 | productRefGroup = 622706152A20065600402F49 /* Products */; 139 | projectDirPath = ""; 140 | projectRoot = ""; 141 | targets = ( 142 | 622706132A20065600402F49 /* share-mount */, 143 | ); 144 | }; 145 | /* End PBXProject section */ 146 | 147 | /* Begin PBXResourcesBuildPhase section */ 148 | 622706122A20065600402F49 /* Resources */ = { 149 | isa = PBXResourcesBuildPhase; 150 | buildActionMask = 2147483647; 151 | files = ( 152 | 6227062E2A200C3300402F49 /* LICENSE in Resources */, 153 | 6227061F2A20065700402F49 /* Preview Assets.xcassets in Resources */, 154 | 6227061C2A20065700402F49 /* Assets.xcassets in Resources */, 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXResourcesBuildPhase section */ 159 | 160 | /* Begin PBXSourcesBuildPhase section */ 161 | 622706102A20065600402F49 /* Sources */ = { 162 | isa = PBXSourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 6227062A2A200A0600402F49 /* MountsView.swift in Sources */, 166 | 622706272A2009B200402F49 /* statusMenu.swift in Sources */, 167 | 6227062C2A200A2400402F49 /* ts_mount.swift in Sources */, 168 | 6227061A2A20065600402F49 /* ContentView.swift in Sources */, 169 | 622706182A20065600402F49 /* share_mountApp.swift in Sources */, 170 | ); 171 | runOnlyForDeploymentPostprocessing = 0; 172 | }; 173 | /* End PBXSourcesBuildPhase section */ 174 | 175 | /* Begin XCBuildConfiguration section */ 176 | 622706212A20065700402F49 /* Debug */ = { 177 | isa = XCBuildConfiguration; 178 | buildSettings = { 179 | ALWAYS_SEARCH_USER_PATHS = NO; 180 | CLANG_ANALYZER_NONNULL = YES; 181 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 182 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 183 | CLANG_ENABLE_MODULES = YES; 184 | CLANG_ENABLE_OBJC_ARC = YES; 185 | CLANG_ENABLE_OBJC_WEAK = YES; 186 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 187 | CLANG_WARN_BOOL_CONVERSION = YES; 188 | CLANG_WARN_COMMA = YES; 189 | CLANG_WARN_CONSTANT_CONVERSION = YES; 190 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 191 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 192 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 193 | CLANG_WARN_EMPTY_BODY = YES; 194 | CLANG_WARN_ENUM_CONVERSION = YES; 195 | CLANG_WARN_INFINITE_RECURSION = YES; 196 | CLANG_WARN_INT_CONVERSION = YES; 197 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 198 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 199 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 200 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 201 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 202 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 203 | CLANG_WARN_STRICT_PROTOTYPES = YES; 204 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 205 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 206 | CLANG_WARN_UNREACHABLE_CODE = YES; 207 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 208 | COPY_PHASE_STRIP = NO; 209 | DEBUG_INFORMATION_FORMAT = dwarf; 210 | ENABLE_STRICT_OBJC_MSGSEND = YES; 211 | ENABLE_TESTABILITY = YES; 212 | GCC_C_LANGUAGE_STANDARD = gnu11; 213 | GCC_DYNAMIC_NO_PIC = NO; 214 | GCC_NO_COMMON_BLOCKS = YES; 215 | GCC_OPTIMIZATION_LEVEL = 0; 216 | GCC_PREPROCESSOR_DEFINITIONS = ( 217 | "DEBUG=1", 218 | "$(inherited)", 219 | ); 220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 222 | GCC_WARN_UNDECLARED_SELECTOR = YES; 223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 224 | GCC_WARN_UNUSED_FUNCTION = YES; 225 | GCC_WARN_UNUSED_VARIABLE = YES; 226 | MACOSX_DEPLOYMENT_TARGET = 13.2; 227 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 228 | MTL_FAST_MATH = YES; 229 | ONLY_ACTIVE_ARCH = YES; 230 | SDKROOT = macosx; 231 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 232 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 233 | }; 234 | name = Debug; 235 | }; 236 | 622706222A20065700402F49 /* Release */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_ENABLE_OBJC_WEAK = YES; 246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_COMMA = YES; 249 | CLANG_WARN_CONSTANT_CONVERSION = YES; 250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 252 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 253 | CLANG_WARN_EMPTY_BODY = YES; 254 | CLANG_WARN_ENUM_CONVERSION = YES; 255 | CLANG_WARN_INFINITE_RECURSION = YES; 256 | CLANG_WARN_INT_CONVERSION = YES; 257 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 258 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 259 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 260 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 261 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 262 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 263 | CLANG_WARN_STRICT_PROTOTYPES = YES; 264 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 265 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | COPY_PHASE_STRIP = NO; 269 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 270 | ENABLE_NS_ASSERTIONS = NO; 271 | ENABLE_STRICT_OBJC_MSGSEND = YES; 272 | GCC_C_LANGUAGE_STANDARD = gnu11; 273 | GCC_NO_COMMON_BLOCKS = YES; 274 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 275 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 276 | GCC_WARN_UNDECLARED_SELECTOR = YES; 277 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 278 | GCC_WARN_UNUSED_FUNCTION = YES; 279 | GCC_WARN_UNUSED_VARIABLE = YES; 280 | MACOSX_DEPLOYMENT_TARGET = 13.2; 281 | MTL_ENABLE_DEBUG_INFO = NO; 282 | MTL_FAST_MATH = YES; 283 | SDKROOT = macosx; 284 | SWIFT_COMPILATION_MODE = wholemodule; 285 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 286 | }; 287 | name = Release; 288 | }; 289 | 622706242A20065700402F49 /* Debug */ = { 290 | isa = XCBuildConfiguration; 291 | buildSettings = { 292 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 293 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 294 | CODE_SIGN_ENTITLEMENTS = "share-mount/share_mount.entitlements"; 295 | CODE_SIGN_STYLE = Automatic; 296 | COMBINE_HIDPI_IMAGES = YES; 297 | CURRENT_PROJECT_VERSION = 1; 298 | DEVELOPMENT_ASSET_PATHS = "\"share-mount/Preview Content\""; 299 | DEVELOPMENT_TEAM = 535LJ3X468; 300 | ENABLE_HARDENED_RUNTIME = YES; 301 | ENABLE_PREVIEWS = YES; 302 | GENERATE_INFOPLIST_FILE = YES; 303 | INFOPLIST_KEY_LSUIElement = YES; 304 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 305 | LD_RUNPATH_SEARCH_PATHS = ( 306 | "$(inherited)", 307 | "@executable_path/../Frameworks", 308 | ); 309 | MARKETING_VERSION = 1.0; 310 | PRODUCT_BUNDLE_IDENTIFIER = "edu.jpcatholic.share-mount"; 311 | PRODUCT_NAME = "$(TARGET_NAME)"; 312 | SWIFT_EMIT_LOC_STRINGS = YES; 313 | SWIFT_VERSION = 5.0; 314 | }; 315 | name = Debug; 316 | }; 317 | 622706252A20065700402F49 /* Release */ = { 318 | isa = XCBuildConfiguration; 319 | buildSettings = { 320 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 321 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 322 | CODE_SIGN_ENTITLEMENTS = "share-mount/share_mount.entitlements"; 323 | CODE_SIGN_STYLE = Automatic; 324 | COMBINE_HIDPI_IMAGES = YES; 325 | CURRENT_PROJECT_VERSION = 1; 326 | DEVELOPMENT_ASSET_PATHS = "\"share-mount/Preview Content\""; 327 | DEVELOPMENT_TEAM = 535LJ3X468; 328 | ENABLE_HARDENED_RUNTIME = YES; 329 | ENABLE_PREVIEWS = YES; 330 | GENERATE_INFOPLIST_FILE = YES; 331 | INFOPLIST_KEY_LSUIElement = YES; 332 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 333 | LD_RUNPATH_SEARCH_PATHS = ( 334 | "$(inherited)", 335 | "@executable_path/../Frameworks", 336 | ); 337 | MARKETING_VERSION = 1.0; 338 | PRODUCT_BUNDLE_IDENTIFIER = "edu.jpcatholic.share-mount"; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | SWIFT_EMIT_LOC_STRINGS = YES; 341 | SWIFT_VERSION = 5.0; 342 | }; 343 | name = Release; 344 | }; 345 | /* End XCBuildConfiguration section */ 346 | 347 | /* Begin XCConfigurationList section */ 348 | 6227060F2A20065600402F49 /* Build configuration list for PBXProject "share-mount" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | 622706212A20065700402F49 /* Debug */, 352 | 622706222A20065700402F49 /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | 622706232A20065700402F49 /* Build configuration list for PBXNativeTarget "share-mount" */ = { 358 | isa = XCConfigurationList; 359 | buildConfigurations = ( 360 | 622706242A20065700402F49 /* Debug */, 361 | 622706252A20065700402F49 /* Release */, 362 | ); 363 | defaultConfigurationIsVisible = 0; 364 | defaultConfigurationName = Release; 365 | }; 366 | /* End XCConfigurationList section */ 367 | }; 368 | rootObject = 6227060C2A20065600402F49 /* Project object */; 369 | } 370 | -------------------------------------------------------------------------------- /share-mount.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /share-mount.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /share-mount.xcodeproj/xcuserdata/kmeziere02.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | share-mount.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /share-mount/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /share-mount/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /share-mount/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /share-mount/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // share-mount 4 | // 5 | // Created by Kevin Meziere on 5/25/23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | VStack { 13 | Image(systemName: "globe") 14 | .imageScale(.large) 15 | .foregroundColor(.accentColor) 16 | Text("Unreachable location. File a ticket. 1554ba15-0d21-4b80-a052-a3eb297dfb2d") 17 | } 18 | .padding() 19 | } 20 | } 21 | 22 | 23 | struct ContentView_Previews: PreviewProvider { 24 | static var previews: some View { 25 | ContentView() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /share-mount/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /share-mount/mounts/MountsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MountsView.swift 3 | // Quick Tasks 4 | // 5 | // Created by Kevin Meziere on 3/8/23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct MountsView: View { 11 | 12 | @Environment(\.openURL) private var openURL 13 | 14 | @State var smbTargets: peersResult = .Ok([]) 15 | //[(String, String, Optional)] = [] 16 | 17 | let timer = Timer.publish(every: 60, on: .main, in: .common).autoconnect() 18 | 19 | 20 | var body: some View { 21 | VStack{ 22 | HStack{ 23 | Spacer() 24 | Text("My Shares").fontWeight(.heavy) 25 | Button(action: { smbTargets = ts_smb_peers()}, label: { Image(systemName: "arrow.clockwise") }).buttonStyle(.borderless) 26 | Spacer() 27 | }.padding() 28 | 29 | switch smbTargets { 30 | case .Ok(let r_smbTargets): 31 | ForEach(r_smbTargets, id: \.0) { smbTarget in 32 | Button(action: { 33 | 34 | if let u = smbTarget.2 { 35 | finder_open(url:u.formatted()) 36 | } 37 | else{ 38 | mount_smb_peer(peer: smbTarget.0) 39 | smbTargets = ts_smb_peers() 40 | } 41 | }, label: { 42 | HStack { 43 | if smbTarget.2 != nil { 44 | Image(systemName: "externaldrive.connected.to.line.below.fill") 45 | .foregroundStyle(.blue, .black) 46 | } 47 | else { 48 | Image(systemName: "externaldrive.connected.to.line.below") 49 | } 50 | Text(smbTarget.1) 51 | } 52 | }).buttonStyle(.borderless).frame(alignment: .leading) 53 | } 54 | case .Error(let msg): 55 | Text(msg) 56 | } 57 | 58 | Spacer() 59 | }.onReceive(timer) { input in 60 | smbTargets = ts_smb_peers() 61 | }.onAppear(){ 62 | smbTargets = ts_smb_peers() 63 | } 64 | } 65 | } 66 | 67 | struct MountsView_Previews: PreviewProvider { 68 | static var previews: some View { 69 | MountsView() 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /share-mount/share_mount.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /share-mount/share_mountApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // share_mountApp.swift 3 | // share-mount 4 | // 5 | // Created by Kevin Meziere on 5/25/23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct share_mountApp: App { 12 | @NSApplicationDelegateAdaptor(AppDelegate.self) var delegate 13 | var body: some Scene { 14 | WindowGroup { 15 | ContentView() 16 | } 17 | } 18 | } 19 | 20 | class AppDelegate: NSObject,NSApplicationDelegate{ 21 | 22 | var statusItem: NSStatusItem? 23 | var popOver = NSPopover() 24 | 25 | func applicationDidFinishLaunching(_ notification: Notification) { 26 | 27 | let menuView = statusMenu() 28 | 29 | popOver.behavior = .transient 30 | popOver.animates = true 31 | popOver.contentViewController = NSViewController() 32 | popOver.contentViewController?.view = NSHostingView(rootView: menuView) 33 | 34 | statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) 35 | 36 | if let MenuButton = statusItem?.button{ 37 | MenuButton.image = NSImage(systemSymbolName:"shield", accessibilityDescription: nil) 38 | MenuButton.action = #selector(MenuButtonToggle) 39 | } 40 | } 41 | @objc func MenuButtonToggle(sender: AnyObject){ 42 | if popOver.isShown { 43 | popOver.performClose(sender) 44 | } 45 | else{ 46 | if let menuButton = statusItem?.button{ 47 | self.popOver.show(relativeTo: menuButton.bounds, of: menuButton, preferredEdge: NSRectEdge.minY) 48 | popOver.contentViewController?.view.window?.makeKey() 49 | } 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /share-mount/statusMenu.swift: -------------------------------------------------------------------------------- 1 | // 2 | // statusMenu.swift 3 | // Quick Tasks 4 | // 5 | // Created by Kevin Meziere on 3/8/23. 6 | // 7 | 8 | import SwiftUI 9 | 10 | 11 | enum NavigationItem { 12 | case agenda 13 | case calendar 14 | case materie 15 | case subjects 16 | } 17 | 18 | struct statusMenu: View { 19 | 20 | // @Environment(\.managedObjectContext) var moc 21 | // @Binding var selection : Set 22 | 23 | var body: some View { 24 | HStack{ 25 | //List() { 26 | VStack(alignment:.leading){ 27 | Spacer() 28 | Button("\(Image(systemName: "globe")) Shares") { 29 | }.buttonStyle(.borderless).tint(Color(red: 0.8, green: 0.8, blue:0.8)).fontWeight(.semibold) 30 | Spacer() 31 | Button("\(Image(systemName: "power")) Quit") { 32 | NSApplication.shared.terminate(nil) 33 | }.buttonStyle(.borderless).tint(Color(red: 0.5, green: 0.5, blue:0.5)).padding() 34 | }.frame(width: 100, height: 300).background(Color(red: 0.66, green: 0.2, blue:0.235)) 35 | 36 | Spacer() 37 | 38 | MountsView() 39 | Spacer() 40 | } 41 | .frame(width: 350, height: 300) 42 | } 43 | } 44 | 45 | struct statusMenu_Previews: PreviewProvider { 46 | static var previews: some View { 47 | statusMenu() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /share-mount/ts_mount.swift: -------------------------------------------------------------------------------- 1 | // 2 | // wg_mount.swift 3 | // Quick Tasks 4 | // 5 | // Created by Kevin Meziere on 3/1/23. 6 | // 7 | 8 | import Foundation 9 | import NetFS 10 | 11 | struct tsStatus: Decodable { 12 | let Peer: [String: tsPeer] 13 | let BackendState: String 14 | } 15 | 16 | struct tsPeer: Decodable { 17 | let ID: String 18 | let HostName: String 19 | let DNSName: String 20 | let Tags: [String] 21 | } 22 | 23 | enum peersResult { 24 | case Ok([(String, String, Optional)]) 25 | case Error(String) 26 | } 27 | 28 | func finder_open(url:String) { 29 | do { 30 | try safeShell("/usr/bin/open " + url) 31 | } 32 | catch { 33 | print("\(error)") //handle or silence the error here 34 | } 35 | 36 | } 37 | 38 | func ts_smb_peers() -> peersResult { 39 | var result:[(String, String, Optional)] = [] 40 | do { 41 | let status = try safeShell("/Applications/Tailscale.app/Contents/MacOS/Tailscale status --json") 42 | let decoded = try JSONDecoder().decode(tsStatus.self, from: Data(status.utf8)) 43 | if decoded.BackendState == "Running"{ 44 | for(peer) in decoded.Peer { 45 | for(tag) in peer.value.Tags { 46 | if tag.contains("smb") && !result.contains(where: {(k,_, _) in 47 | if k == peer.value.DNSName {return true} 48 | else {return false}}){ 49 | result.append( 50 | (peer.value.DNSName, 51 | peer.value.DNSName.components(separatedBy: ".")[0], nil) 52 | ) 53 | } 54 | } 55 | } 56 | } 57 | else { 58 | return peersResult.Error("Tailscale Not Connected") 59 | } 60 | } 61 | catch { 62 | return peersResult.Error("\(error)") 63 | } 64 | 65 | let keys: [URLResourceKey] = [.volumeURLForRemountingKey, .volumeURLKey] 66 | let paths = FileManager().mountedVolumeURLs(includingResourceValuesForKeys: keys, options: []) 67 | if let urls = paths { 68 | for url in urls { 69 | let components = url.pathComponents 70 | if components.count > 1 71 | && components[1] == "Volumes" 72 | { 73 | let remountUrl = try? url.resourceValues(forKeys: Set(arrayLiteral: .volumeURLForRemountingKey)).volumeURLForRemounting 74 | if let k = result.firstIndex(where: {(_,host,_) in 75 | remountUrl?.formatted().contains(host) ?? false 76 | }){ 77 | 78 | result[k].2 = url 79 | } 80 | } 81 | } 82 | } 83 | 84 | return peersResult.Ok(result) 85 | } 86 | 87 | func mount_smb_peer(peer:String) { 88 | let kNAUIOptionKey = "UIOption" 89 | let kNAUIOptionNoUI = "NoUI" 90 | let kNetFSUseGuestKey = "Guest" 91 | 92 | let dict = NSMutableDictionary() 93 | dict[kNAUIOptionKey] = kNAUIOptionNoUI 94 | dict[kNetFSUseGuestKey] = NSNumber(value: true) 95 | 96 | 97 | let url = URL(string: "smb://" + peer + "/share")! 98 | let err = NetFSMountURLSync( 99 | url as NSURL, // url 100 | nil, // mountpath 101 | nil, // user 102 | nil, // passwd 103 | dict, // open_options 104 | nil, // mount_options, 105 | nil // mountpoints 106 | ) 107 | print(err) 108 | } 109 | 110 | // See https://stackoverflow.com/questions/26971240/how-do-i-run-a-terminal-command-in-a-swift-script-e-g-xcodebuild 111 | // updated answer by user3064009 112 | 113 | @discardableResult // Add to suppress warnings when you don't want/need a result 114 | func safeShell(_ command: String) throws -> String { 115 | let task = Process() 116 | let pipe = Pipe() 117 | 118 | task.standardOutput = pipe 119 | task.standardError = pipe 120 | task.arguments = ["-c", command] 121 | task.executableURL = URL(fileURLWithPath: "/bin/zsh") //<--updated 122 | task.standardInput = nil 123 | 124 | try task.run() //<--updated 125 | 126 | let data = pipe.fileHandleForReading.readDataToEndOfFile() 127 | let output = String(data: data, encoding: .utf8)! 128 | 129 | return output 130 | } 131 | --------------------------------------------------------------------------------