From 724860c272afb7fe5a02645ef1c1b8d208d897f3 Mon Sep 17 00:00:00 2001 From: ivar Date: Thu, 4 Dec 2025 00:17:16 +0100 Subject: POC auth in app --- api/WhatApi/Endpoints/DownloadContentEndpoint.cs | 2 +- api/WhatApi/Endpoints/GetLoginPageEndpoint.cs | 12 +++++++ api/WhatApi/Endpoints/LoginEndpoint.cs | 5 +-- api/WhatApi/Program.cs | 2 +- api/WhatApi/Properties/launchSettings.json | 2 +- api/WhatApi/Templates/TemplateFulfiller.cs | 6 ++++ api/WhatApi/Templates/web_login.liquid | 37 ++++++++++++++++++++ api/WhatApi/WhatApi.csproj | 1 + api/http/login.http | 6 ++-- ios/H--appen-Info.plist | 5 ++- "ios/H\303\246-appen.xcodeproj/project.pbxproj" | 17 --------- .../xcshareddata/swiftpm/Package.resolved" | 24 ++----------- "ios/H\303\246-appen/Auth.swift" | 40 ++++++++++++++++++++++ "ios/H\303\246-appen/ProfileContentView.swift" | 28 +++++++++++++++ "ios/H\303\246-appen/TabBarView.swift" | 4 +-- 15 files changed, 142 insertions(+), 49 deletions(-) create mode 100644 api/WhatApi/Endpoints/GetLoginPageEndpoint.cs create mode 100644 api/WhatApi/Templates/web_login.liquid create mode 100644 "ios/H\303\246-appen/Auth.swift" create mode 100644 "ios/H\303\246-appen/ProfileContentView.swift" diff --git a/api/WhatApi/Endpoints/DownloadContentEndpoint.cs b/api/WhatApi/Endpoints/DownloadContentEndpoint.cs index 34e51e8..dbbe57f 100644 --- a/api/WhatApi/Endpoints/DownloadContentEndpoint.cs +++ b/api/WhatApi/Endpoints/DownloadContentEndpoint.cs @@ -14,4 +14,4 @@ public class DownloadContentEndpoint : BaseEndpoint return NotFound(); } } -} \ No newline at end of file +} diff --git a/api/WhatApi/Endpoints/GetLoginPageEndpoint.cs b/api/WhatApi/Endpoints/GetLoginPageEndpoint.cs new file mode 100644 index 0000000..dd17669 --- /dev/null +++ b/api/WhatApi/Endpoints/GetLoginPageEndpoint.cs @@ -0,0 +1,12 @@ +using WhatApi.Templates; + +namespace WhatApi.Endpoints; + +public class GetLoginPageEndpoint : BaseEndpoint +{ + [AllowAnonymous] + [HttpGet("~/login")] + public ActionResult Handle() { + return Content(TemplateFulfiller.WebLoginPage(), "text/html"); + } +} \ No newline at end of file diff --git a/api/WhatApi/Endpoints/LoginEndpoint.cs b/api/WhatApi/Endpoints/LoginEndpoint.cs index ee697ef..cb76696 100644 --- a/api/WhatApi/Endpoints/LoginEndpoint.cs +++ b/api/WhatApi/Endpoints/LoginEndpoint.cs @@ -13,8 +13,9 @@ public class LoginEndpoint(AppDatabase db, IConfiguration configuration) : BaseE public required string Password { get; set; } } + [AllowAnonymous] [HttpPost("~/login")] - public async Task HandleAsync(LoginRequest login, CancellationToken ct = default) { + public async Task HandleAsync([FromForm] LoginRequest login, CancellationToken ct = default) { var user = await db.Users.FirstOrDefaultAsync(c => c.Name == login.Username, ct); if (user?.PasswordHash is null) return Unauthorized(); @@ -47,6 +48,6 @@ public class LoginEndpoint(AppDatabase db, IConfiguration configuration) : BaseE var tokenString = tokenHandler.WriteToken(token); user.SetLastSeen(); await db.SaveChangesAsync(ct); - return Ok(tokenString); + return Redirect("what://lcb?code=" + tokenString); } } \ No newline at end of file diff --git a/api/WhatApi/Program.cs b/api/WhatApi/Program.cs index 7d9c1b4..3375e09 100644 --- a/api/WhatApi/Program.cs +++ b/api/WhatApi/Program.cs @@ -93,7 +93,7 @@ app.UseMiddleware(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); -app.MapGet("/", () => Results.Redirect("/map")); +app.MapGet("/", () => Results.Redirect("/login")); app.Run(); return 0; \ No newline at end of file diff --git a/api/WhatApi/Properties/launchSettings.json b/api/WhatApi/Properties/launchSettings.json index 581ee7b..73724a7 100644 --- a/api/WhatApi/Properties/launchSettings.json +++ b/api/WhatApi/Properties/launchSettings.json @@ -5,7 +5,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, - "applicationUrl": "http://localhost:5281", + "applicationUrl": "http://0.0.0.0:5281", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/api/WhatApi/Templates/TemplateFulfiller.cs b/api/WhatApi/Templates/TemplateFulfiller.cs index 19d3bde..3433701 100644 --- a/api/WhatApi/Templates/TemplateFulfiller.cs +++ b/api/WhatApi/Templates/TemplateFulfiller.cs @@ -8,6 +8,7 @@ public class TemplateFulfiller private static readonly string TemplateDirectory = Path.Combine(Directory.GetCurrentDirectory(), "Templates"); private static string WebMapTemplate => File.ReadAllText(Path.Combine(TemplateDirectory, "web_map.liquid")); private static string WebUploadTemplate => File.ReadAllText(Path.Combine(TemplateDirectory, "web_upload.liquid")); + private static string WebLoginTemplate => File.ReadAllText(Path.Combine(TemplateDirectory, "web_login.liquid")); public static string WebMapPage(object? data = null) { Parser.TryParse(WebMapTemplate, out var template); @@ -20,4 +21,9 @@ public class TemplateFulfiller var context = data is null ? new TemplateContext() : new TemplateContext(data); return template.Render(context); } + public static string WebLoginPage(object? data = null) { + Parser.TryParse(WebLoginTemplate, out var template); + var context = data is null ? new TemplateContext() : new TemplateContext(data); + return template.Render(context); + } } \ No newline at end of file diff --git a/api/WhatApi/Templates/web_login.liquid b/api/WhatApi/Templates/web_login.liquid new file mode 100644 index 0000000..e9e545d --- /dev/null +++ b/api/WhatApi/Templates/web_login.liquid @@ -0,0 +1,37 @@ + + + + + + + + Login + + +
+ + + +
+ + \ No newline at end of file diff --git a/api/WhatApi/WhatApi.csproj b/api/WhatApi/WhatApi.csproj index 91f3d3f..52044a1 100644 --- a/api/WhatApi/WhatApi.csproj +++ b/api/WhatApi/WhatApi.csproj @@ -13,6 +13,7 @@ .dockerignore + diff --git a/api/http/login.http b/api/http/login.http index 8ebba0c..2c1438f 100644 --- a/api/http/login.http +++ b/api/http/login.http @@ -11,7 +11,7 @@ POST {{canonical}}/create-user Content-Type: application/json { - "name": "ivarsu", - "email": "ivarsu@oiee.no", - "password": "ivargangertre" + "name": "", + "email": "", + "password": "" } diff --git a/ios/H--appen-Info.plist b/ios/H--appen-Info.plist index 0c67376..121e93f 100644 --- a/ios/H--appen-Info.plist +++ b/ios/H--appen-Info.plist @@ -1,5 +1,8 @@ - + + CFBundleDocumentTypes + + diff --git "a/ios/H\303\246-appen.xcodeproj/project.pbxproj" "b/ios/H\303\246-appen.xcodeproj/project.pbxproj" index 89a4707..0d15cca 100644 --- "a/ios/H\303\246-appen.xcodeproj/project.pbxproj" +++ "b/ios/H\303\246-appen.xcodeproj/project.pbxproj" @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 1B9B791B2E7A06C300D5AF05 /* GISTools in Frameworks */ = {isa = PBXBuildFile; productRef = 1B9B791A2E7A06C300D5AF05 /* GISTools */; }; - 1B9E76382EA6DCD200170C86 /* MijickCamera in Frameworks */ = {isa = PBXBuildFile; productRef = 1B9E76372EA6DCD200170C86 /* MijickCamera */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -28,7 +27,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 1B9E76382EA6DCD200170C86 /* MijickCamera in Frameworks */, 1B9B791B2E7A06C300D5AF05 /* GISTools in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -73,7 +71,6 @@ name = "Hæ-appen"; packageProductDependencies = ( 1B9B791A2E7A06C300D5AF05 /* GISTools */, - 1B9E76372EA6DCD200170C86 /* MijickCamera */, ); productName = "Hæ-appen"; productReference = 1B9B79032E79DFB800D5AF05 /* Hæ-appen.app */; @@ -105,7 +102,6 @@ minimizedProjectReferenceProxies = 1; packageReferences = ( 1B9B79192E7A06C300D5AF05 /* XCRemoteSwiftPackageReference "gis-tools" */, - 1B9E76362EA6DCD200170C86 /* XCRemoteSwiftPackageReference "Camera" */, ); preferredProjectObjectVersion = 77; productRefGroup = 1B9B79042E79DFB800D5AF05 /* Products */; @@ -373,14 +369,6 @@ minimumVersion = 1.3.0; }; }; - 1B9E76362EA6DCD200170C86 /* XCRemoteSwiftPackageReference "Camera" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Mijick/Camera.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.0.3; - }; - }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -389,11 +377,6 @@ package = 1B9B79192E7A06C300D5AF05 /* XCRemoteSwiftPackageReference "gis-tools" */; productName = GISTools; }; - 1B9E76372EA6DCD200170C86 /* MijickCamera */ = { - isa = XCSwiftPackageProductDependency; - package = 1B9E76362EA6DCD200170C86 /* XCRemoteSwiftPackageReference "Camera" */; - productName = MijickCamera; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 1B9B78FB2E79DFB800D5AF05 /* Project object */; diff --git "a/ios/H\303\246-appen.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved" "b/ios/H\303\246-appen.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved" index 8b323a8..e4a6dc8 100644 --- "a/ios/H\303\246-appen.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved" +++ "b/ios/H\303\246-appen.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved" @@ -1,31 +1,13 @@ { - "originHash" : "632a8f8853aa0d419765a7b78fcd66e62b7f9aa58329c89492d24f6985316ee5", + "originHash" : "a1cca039aa1704ebabd161056262205e26a4daf8a42ebb77bc98b0b620ee8fb4", "pins" : [ - { - "identity" : "camera", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Mijick/Camera.git", - "state" : { - "revision" : "0f02348fcc8fbbc9224c7fbf444f182dc25d0b40", - "version" : "3.0.3" - } - }, { "identity" : "gis-tools", "kind" : "remoteSourceControl", "location" : "https://github.com/Outdooractive/gis-tools.git", "state" : { - "revision" : "f7a4d2aa2acf771b79a91150f359bcd84de9ceac", - "version" : "1.13.2" - } - }, - { - "identity" : "timer", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Mijick/Timer", - "state" : { - "revision" : "342371c33c3f084d82a4818447ba77d858064c85", - "version" : "2.0.0" + "revision" : "30e1e1f0af115822e5844792f2322107c81b2c5e", + "version" : "1.3.0" } } ], diff --git "a/ios/H\303\246-appen/Auth.swift" "b/ios/H\303\246-appen/Auth.swift" new file mode 100644 index 0000000..09da4af --- /dev/null +++ "b/ios/H\303\246-appen/Auth.swift" @@ -0,0 +1,40 @@ +// +// Auth.swift +// Hæ-appen +// +// Created by Ivar Løvlie on 03/12/2025. +// +import SwiftUI +import AuthenticationServices +import OSLog + +struct Auth { + let logger = Logger(subsystem: "com.yourcompany.app", category: "auth") + func login() -> Void { + guard let url = URL(string:"http://192.168.0.103:5281/login") else {return} + let session = ASWebAuthenticationSession(url: url, callbackURLScheme: "what") { + callbackURL, error in + guard error == nil, let callbackURL = callbackURL else { return } + let queryItems = URLComponents(string: callbackURL.absoluteString)?.queryItems + _ = queryItems?.filter({ $0.name == "code" }).first?.value + } + let vc = AuthViewController() + session.presentationContextProvider = vc + session.start() + return + } + func register() -> Void { + return + } + func logout() -> Void { + return + } + +} + +class AuthViewController: UIViewController, ASWebAuthenticationPresentationContextProviding +{ + func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { + return ASPresentationAnchor() + } +} diff --git "a/ios/H\303\246-appen/ProfileContentView.swift" "b/ios/H\303\246-appen/ProfileContentView.swift" new file mode 100644 index 0000000..af5cd33 --- /dev/null +++ "b/ios/H\303\246-appen/ProfileContentView.swift" @@ -0,0 +1,28 @@ +// +// ProfileContentView.swift +// Hæ-appen +// +// Created by Ivar Løvlie on 03/12/2025. +// + +import SwiftUI + +struct ProfileContentView : View { + let auth = Auth() + + var body: some View { + VStack { + Text("Halla!") + .font(.largeTitle) + HStack + { + Button("Logg på", systemImage: "hand.raised.square.on.square") { + auth.login() + } + Button("Registrer deg", systemImage: "hand.raised.square.on.square") { + auth.register() + } + }.buttonStyle(.borderless) + } + } +} diff --git "a/ios/H\303\246-appen/TabBarView.swift" "b/ios/H\303\246-appen/TabBarView.swift" index 2a88336..59896c5 100644 --- "a/ios/H\303\246-appen/TabBarView.swift" +++ "b/ios/H\303\246-appen/TabBarView.swift" @@ -16,8 +16,8 @@ struct TabBarView : View { Tab("Resten", systemImage: "option") { MapContentView() } - Tab("", systemImage: "camera.shutter.button.fill", role: .search) { - CameraContentView() + Tab("Profil", systemImage: "person", role: .search) { + ProfileContentView() } } } -- cgit v1.3