Skip to content

Commit

Permalink
Merge pull request #254 from b123400/fix-245
Browse files Browse the repository at this point in the history
Implement ADSwiss SAML and E-rezept in prescription PDF
  • Loading branch information
zdavatz authored Jul 11, 2023
2 parents 8654be9 + b8e00e1 commit 2b4ee4d
Show file tree
Hide file tree
Showing 33 changed files with 1,496 additions and 131 deletions.
95 changes: 95 additions & 0 deletions AmiKo.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

87 changes: 60 additions & 27 deletions AmiKoOSX/Base.lproj/MLPreferencesWindowController.xib

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions AmiKoOSX/MLADSwissOAuthWindowController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// MLADSwissOAuthWindowController.h
// AmiKo
//
// Created by b123400 on 2023/07/06.
// Copyright © 2023 Ywesee GmbH. All rights reserved.
//

#import "MLHINOAuthWindowController.h"

NS_ASSUME_NONNULL_BEGIN

@interface MLADSwissOAuthWindowController : MLHINOAuthWindowController

@end

NS_ASSUME_NONNULL_END
35 changes: 35 additions & 0 deletions AmiKoOSX/MLADSwissOAuthWindowController.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// MLADSwissOAuthWindowController.m
// AmiKo
//
// Created by b123400 on 2023/07/06.
// Copyright © 2023 Ywesee GmbH. All rights reserved.
//

#import "MLADSwissOAuthWindowController.h"
#import "MLHINClient.h"
#import "MLPersistenceManager.h"

@interface MLADSwissOAuthWindowController ()

@end

@implementation MLADSwissOAuthWindowController

- (NSURL *)authURL {
return [[MLHINClient shared] authURLForADSwiss];
}

- (void)receivedTokens:(id)tokens {
[[MLPersistenceManager shared] setHINADSwissTokens:tokens];
[self.window.sheetParent endSheet:self.window
returnCode:NSModalResponseOK];
}

- (void)windowDidLoad {
[super windowDidLoad];

// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}

@end
18 changes: 18 additions & 0 deletions AmiKoOSX/MLADSwissSAMLWindowController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// MLADSwissSAMLWindowController.h
// AmiKo
//
// Created by b123400 on 2023/07/09.
// Copyright © 2023 Ywesee GmbH. All rights reserved.
//

#import "MLHINOAuthWindowController.h"
#import "MLHINADSwissSaml.h"

NS_ASSUME_NONNULL_BEGIN

@interface MLADSwissSAMLWindowController : NSWindowController

@end

NS_ASSUME_NONNULL_END
126 changes: 126 additions & 0 deletions AmiKoOSX/MLADSwissSAMLWindowController.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//
// MLADSwissSAMLWindowController.m
// AmiKo
//
// Created by b123400 on 2023/07/09.
// Copyright © 2023 Ywesee GmbH. All rights reserved.
//

#import "MLADSwissSAMLWindowController.h"
#import "MLPersistenceManager.h"
#import "MLHINClient.h"
#import <WebKit/WebKit.h>

@interface MLADSwissSAMLWindowController () <WKNavigationDelegate>

@property (weak) IBOutlet WKWebView *webView;
@property (weak) IBOutlet NSProgressIndicator *loadingIndicator;
@property (weak) IBOutlet NSTextField *statusLabel;

@end

@implementation MLADSwissSAMLWindowController

- (instancetype)init {
if (self = [super initWithWindowNibName:@"MLADSwissSAMLWindowController"]) {

}
return self;
}

- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
NSURL *url = navigationAction.request.URL;
typeof(self) __weak _self = self;
if ([url.host isEqualTo:@"localhost"] && [url.port isEqualTo:@(8080)] && [url.path isEqualTo:@"/callback"]) {
decisionHandler(WKNavigationActionPolicyCancel);
dispatch_async(dispatch_get_main_queue(), ^{
[_self.loadingIndicator startAnimation:_self];
[_self displayStatus:NSLocalizedString(@"Loading: Received callback, fetching Auth handle", @"")];
});
NSLog(@"url: %@", url);
// http://localhost:8080/callback?auth_code=xxxxxx
NSURLComponents *components = [NSURLComponents componentsWithURL:url
resolvingAgainstBaseURL:NO];
for (NSURLQueryItem *query in [components queryItems]) {
if ([query.name isEqualTo:@"auth_code"]) {
[[MLHINClient shared] fetchADSwissAuthHandleWithToken:[[MLPersistenceManager shared] HINADSwissTokens]
authCode:query.value
completion:^(NSError * _Nullable error, NSString * _Nullable authHandle) {
NSLog(@"received Auth Handle1 %@ %@", error, authHandle);
if (error) {
[_self displayError:error];
return;
}
if (!authHandle) {
[_self displayError:[NSError errorWithDomain:@"com.ywesee.AmikoDesitin"
code:0
userInfo:@{
NSLocalizedDescriptionKey: @"Invalid authHandle"
}]];
return;
}
[_self displayStatus:NSLocalizedString(@"Received Auth Handle", @"")];
[[MLPersistenceManager shared] setHINADSwissAuthHandle:authHandle];
dispatch_async(dispatch_get_main_queue(), ^{
[_self.window.sheetParent endSheet:_self.window returnCode:NSModalResponseOK];
});
}];
break;
}
}
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
[self.loadingIndicator stopAnimation:self];
}

- (void)windowDidLoad {
[super windowDidLoad];
[self displayStatus:NSLocalizedString(@"Loading SAML URL", @"")];
[self.loadingIndicator startAnimation:self];
MLHINTokens *tokens = [[MLPersistenceManager shared] HINADSwissTokens];
if (!tokens) {
NSLog(@"Token not found, not loading SAML");
return;
}
typeof(self) __weak _self = self;
[[MLHINClient shared] fetchADSwissSAMLWithToken:tokens
completion:^(NSError * _Nullable error, MLHINADSwissSaml * _Nonnull result) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
[[NSAlert alertWithError:error] runModal];
return;
}
[_self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:result.epdAuthUrl]]];
});
}];
}

- (IBAction)closeClicked:(id)sender {
[self.window.sheetParent endSheet:self.window
returnCode:NSModalResponseCancel];
}

- (void)displayError:(NSError *)error {
dispatch_async(dispatch_get_main_queue(), ^{
[[NSAlert alertWithError:error] runModal];
});
}

- (void)displayStatus:(NSString *)status {
if ([NSThread isMainThread]) {
self.statusLabel.stringValue = status;
} else {
typeof(self) __weak _self = self;
dispatch_async(dispatch_get_main_queue(), ^{
_self.statusLabel.stringValue = status;
});
}
}

@end
80 changes: 80 additions & 0 deletions AmiKoOSX/MLADSwissSAMLWindowController.xib
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
<plugIn identifier="com.apple.WebKit2IBPlugin" version="21225"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MLADSwissSAMLWindowController">
<connections>
<outlet property="loadingIndicator" destination="M2H-Sh-Lbb" id="4d0-Gu-Qpu"/>
<outlet property="statusLabel" destination="1aH-MX-Qdw" id="uUh-J1-7NV"/>
<outlet property="webView" destination="363-5m-h8v" id="gOA-Q8-zCG"/>
<outlet property="window" destination="dx0-Gz-u72" id="ad4-Yh-Bo9"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="dx0-Gz-u72">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="196" y="240" width="800" height="600"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1055"/>
<view key="contentView" id="aYk-wJ-jtB">
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<wkWebView wantsLayer="YES" translatesAutoresizingMaskIntoConstraints="NO" id="363-5m-h8v">
<rect key="frame" x="0.0" y="60" width="800" height="540"/>
<wkWebViewConfiguration key="configuration">
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
<wkPreferences key="preferences"/>
</wkWebViewConfiguration>
<connections>
<outlet property="navigationDelegate" destination="-2" id="eAQ-9G-YwP"/>
</connections>
</wkWebView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="nFd-Rj-Wzg">
<rect key="frame" x="717" y="13" width="70" height="32"/>
<buttonCell key="cell" type="push" title="Close" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Kx8-fT-5L3">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="closeClicked:" target="-2" id="JA6-jL-fto"/>
</connections>
</button>
<progressIndicator maxValue="100" displayedWhenStopped="NO" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="M2H-Sh-Lbb">
<rect key="frame" x="384" y="14" width="32" height="32"/>
</progressIndicator>
<textField horizontalHuggingPriority="249" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="1aH-MX-Qdw">
<rect key="frame" x="18" y="20" width="360" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Status:" id="GcG-Wt-JUf">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="nFd-Rj-Wzg" secondAttribute="trailing" constant="20" symbolic="YES" id="32v-BA-0nw"/>
<constraint firstItem="363-5m-h8v" firstAttribute="leading" secondItem="aYk-wJ-jtB" secondAttribute="leading" id="BO0-fC-f6Q"/>
<constraint firstAttribute="trailing" secondItem="363-5m-h8v" secondAttribute="trailing" id="BdN-6G-oz9"/>
<constraint firstItem="M2H-Sh-Lbb" firstAttribute="leading" secondItem="1aH-MX-Qdw" secondAttribute="trailing" constant="8" symbolic="YES" id="En9-LT-398"/>
<constraint firstItem="M2H-Sh-Lbb" firstAttribute="centerY" secondItem="nFd-Rj-Wzg" secondAttribute="centerY" id="Fhb-IH-WmR"/>
<constraint firstAttribute="bottom" secondItem="nFd-Rj-Wzg" secondAttribute="bottom" constant="20" symbolic="YES" id="JYH-Ps-Z6m"/>
<constraint firstItem="M2H-Sh-Lbb" firstAttribute="centerX" secondItem="363-5m-h8v" secondAttribute="centerX" id="P5G-Ck-sWg"/>
<constraint firstItem="363-5m-h8v" firstAttribute="top" secondItem="aYk-wJ-jtB" secondAttribute="top" id="QH3-zy-lbs"/>
<constraint firstItem="1aH-MX-Qdw" firstAttribute="leading" secondItem="aYk-wJ-jtB" secondAttribute="leading" constant="20" symbolic="YES" id="Sd7-QN-1Pn"/>
<constraint firstItem="nFd-Rj-Wzg" firstAttribute="top" secondItem="363-5m-h8v" secondAttribute="bottom" constant="20" symbolic="YES" id="aO7-ud-79L"/>
<constraint firstAttribute="bottom" secondItem="1aH-MX-Qdw" secondAttribute="bottom" constant="20" symbolic="YES" id="voZ-yh-H2d"/>
</constraints>
</view>
<point key="canvasLocation" x="126" y="144"/>
</window>
</objects>
</document>
6 changes: 6 additions & 0 deletions AmiKoOSX/MLHINOAuthWindowController.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
//

#import <Cocoa/Cocoa.h>
#import "MLHINClient.h"

NS_ASSUME_NONNULL_BEGIN

@interface MLHINOAuthWindowController : NSWindowController

- (NSURL *)authURL;
- (void)receivedTokens:(MLHINTokens *)tokens;
- (void)displayError:(NSError *)error;
- (void)displayStatus:(NSString *)status;

@end

NS_ASSUME_NONNULL_END
Loading

0 comments on commit 2b4ee4d

Please sign in to comment.