mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-10-07 18:22:04 +00:00
feat: add auth support (default and paia)
This commit is contained in:
committed by
Jovan Krunić
parent
046a95ba1d
commit
b5f239ea4e
+1
-1
@@ -41,7 +41,7 @@
|
||||
"unicorn/no-array-callback-reference": "off",
|
||||
"unicorn/prefer-object-from-entries": "off",
|
||||
"unicorn/prevent-abbreviations": [
|
||||
"error",
|
||||
"warn",
|
||||
{
|
||||
"replacements": {
|
||||
"ref": false,
|
||||
|
||||
@@ -3,7 +3,7 @@ apply plugin: 'com.android.application'
|
||||
android {
|
||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "de.any_school.app"
|
||||
applicationId "de.anyschool.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
|
||||
@@ -9,12 +9,15 @@ android {
|
||||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
implementation project(':capacitor-community-http')
|
||||
implementation project(':capacitor-app')
|
||||
implementation project(':capacitor-browser')
|
||||
implementation project(':capacitor-haptics')
|
||||
implementation project(':capacitor-keyboard')
|
||||
implementation project(':capacitor-splash-screen')
|
||||
implementation project(':capacitor-status-bar')
|
||||
implementation project(':capacitor-storage')
|
||||
implementation project(':capacitor-secure-storage-plugin')
|
||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||
implementation "androidx.appcompat:appcompat:1.3.1"
|
||||
}
|
||||
|
||||
@@ -1,49 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="de.any_school.app">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
|
||||
android:name="de.any_school.app.MainActivity"
|
||||
android:label="@string/title_activity_main"
|
||||
android:theme="@style/AppTheme.NoActionBarLaunch"
|
||||
android:launchMode="singleTask">
|
||||
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<manifest package="de.anyschool.app" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
|
||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode" android:label="@string/title_activity_main" android:launchMode="singleTask" android:name="de.anyschool.app.MainActivity" android:theme="@style/AppTheme.NoActionBarLaunch">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="@string/custom_url_scheme" />
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<!-- NEXT LINE'S HOST TO BE GENERATED (SCHOOL SPECIFIC) -->
|
||||
<data android:scheme="https" android:host="mobile.app.uni-frankfurt.de" />
|
||||
<data android:host="mobile.app.uni-frankfurt.de" android:scheme="https" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths"></meta-data>
|
||||
<provider android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<!-- Permissions -->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"appId": "de.any_school.app",
|
||||
"appId": "de.anyschool.app",
|
||||
"appName": "StApps",
|
||||
"webDir": "www",
|
||||
"bundledWebRuntime": false,
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
[
|
||||
{
|
||||
"pkg": "@capacitor-community/http",
|
||||
"classpath": "com.getcapacitor.plugin.http.Http"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/app",
|
||||
"classpath": "com.capacitorjs.plugins.app.AppPlugin"
|
||||
@@ -22,5 +26,13 @@
|
||||
{
|
||||
"pkg": "@capacitor/status-bar",
|
||||
"classpath": "com.capacitorjs.plugins.statusbar.StatusBarPlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "@capacitor/storage",
|
||||
"classpath": "com.capacitorjs.plugins.storage.StoragePlugin"
|
||||
},
|
||||
{
|
||||
"pkg": "capacitor-secure-storage-plugin",
|
||||
"classpath": "com.whitestein.securestorage.SecureStoragePlugin"
|
||||
}
|
||||
]
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package de.any_school.app;
|
||||
package de.anyschool.app;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<resources>
|
||||
<string name="app_name">StApps</string>
|
||||
<string name="title_activity_main">StApps</string>
|
||||
<string name="package_name">de.any_school.app</string>
|
||||
<string name="custom_url_scheme">de.any_school.app</string>
|
||||
<string name="package_name">de.anyschool.app</string>
|
||||
<string name="custom_url_scheme">de.anyschool.app</string>
|
||||
</resources>
|
||||
|
||||
@@ -7,7 +7,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:4.2.1'
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath 'com.google.gms:google-services:4.3.5'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||
|
||||
include ':capacitor-community-http'
|
||||
project(':capacitor-community-http').projectDir = new File('../node_modules/@capacitor-community/http/android')
|
||||
|
||||
include ':capacitor-app'
|
||||
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
|
||||
|
||||
@@ -19,3 +22,9 @@ project(':capacitor-splash-screen').projectDir = new File('../node_modules/@capa
|
||||
|
||||
include ':capacitor-status-bar'
|
||||
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
|
||||
|
||||
include ':capacitor-storage'
|
||||
project(':capacitor-storage').projectDir = new File('../node_modules/@capacitor/storage/android')
|
||||
|
||||
include ':capacitor-secure-storage-plugin'
|
||||
project(':capacitor-secure-storage-plugin').projectDir = new File('../node_modules/capacitor-secure-storage-plugin/android')
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import {CapacitorConfig} from '@capacitor/cli';
|
||||
|
||||
const config: CapacitorConfig = {
|
||||
appId: 'de.any_school.app',
|
||||
appId: 'de.anyschool.app',
|
||||
appName: 'StApps',
|
||||
webDir: 'www',
|
||||
bundledWebRuntime: false,
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget id="de.any_school.app" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<widget id="de.anyschool.app" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<name>StApps</name>
|
||||
<description>An awesome Ionic/Cordova app.</description>
|
||||
<author email="hi@ionicframework" href="http://ionicframework.com/">Ionic Framework Team</author>
|
||||
@@ -21,10 +21,6 @@
|
||||
<preference name="SplashScreen" value="screen" />
|
||||
<preference name="SplashScreenDelay" value="3000" />
|
||||
<plugin name="cordova-plugin-whitelist" spec="1.3.3" />
|
||||
<plugin name="cordova-plugin-device" spec="2.0.2" />
|
||||
<plugin name="cordova-plugin-splashscreen" spec="5.0.2" />
|
||||
<plugin name="cordova-plugin-ionic-webview" spec="2.0.0" />
|
||||
<plugin name="cordova-plugin-ionic-keyboard" spec="2.0.5" />
|
||||
<plugin name="cordova-plugin-geolocation" spec="4.0.1">
|
||||
<variable name="GEOLOCATION_USAGE_DESCRIPTION" value="The app will use your location to provide features for navigation or distances information." />
|
||||
</plugin>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
App/build
|
||||
App/Pods
|
||||
App/Podfile.lock
|
||||
App/App/public
|
||||
DerivedData
|
||||
xcuserdata
|
||||
|
||||
# Cordova plugins for Capacitor
|
||||
capacitor-cordova-ios-plugins
|
||||
@@ -0,0 +1,428 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 48;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30B1FED79650016851F /* Main.storyboard */; };
|
||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504EC30E1FED79650016851F /* Assets.xcassets */; };
|
||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 504EC3101FED79650016851F /* LaunchScreen.storyboard */; };
|
||||
50B271D11FEDC1A000F3C39B /* public in Resources */ = {isa = PBXBuildFile; fileRef = 50B271D01FEDC1A000F3C39B /* public */; };
|
||||
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
504EC3071FED79650016851F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
504EC30C1FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
504EC30E1FED79650016851F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
504EC3111FED79650016851F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
504EC3131FED79650016851F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
50B271D01FEDC1A000F3C39B /* public */ = {isa = PBXFileReference; lastKnownFileType = folder; path = public; sourceTree = "<group>"; };
|
||||
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.release.xcconfig"; sourceTree = "<group>"; };
|
||||
E2D249FB277CB255005492AC /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
||||
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-App/Pods-App.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
504EC3011FED79650016851F /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A084ECDBA7D38E1E42DFC39D /* Pods_App.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AF277DCFFFF123FFC6DF26C7 /* Pods_App.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC2FB1FED79650016851F = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
504EC3061FED79650016851F /* App */,
|
||||
504EC3051FED79650016851F /* Products */,
|
||||
7F8756D8B27F46E3366F6CEA /* Pods */,
|
||||
27E2DDA53C4D2A4D1A88CE4A /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC3051FED79650016851F /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
504EC3041FED79650016851F /* App.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC3061FED79650016851F /* App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E2D249FB277CB255005492AC /* App.entitlements */,
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */,
|
||||
504EC3071FED79650016851F /* AppDelegate.swift */,
|
||||
504EC30B1FED79650016851F /* Main.storyboard */,
|
||||
504EC30E1FED79650016851F /* Assets.xcassets */,
|
||||
504EC3101FED79650016851F /* LaunchScreen.storyboard */,
|
||||
504EC3131FED79650016851F /* Info.plist */,
|
||||
2FAD9762203C412B000D30F8 /* config.xml */,
|
||||
50B271D01FEDC1A000F3C39B /* public */,
|
||||
);
|
||||
path = App;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7F8756D8B27F46E3366F6CEA /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */,
|
||||
AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
504EC3031FED79650016851F /* App */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */;
|
||||
buildPhases = (
|
||||
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */,
|
||||
504EC3001FED79650016851F /* Sources */,
|
||||
504EC3011FED79650016851F /* Frameworks */,
|
||||
504EC3021FED79650016851F /* Resources */,
|
||||
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */,
|
||||
0C3780443725062B779B937E /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = App;
|
||||
productName = App;
|
||||
productReference = 504EC3041FED79650016851F /* App.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
504EC2FC1FED79650016851F /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 0920;
|
||||
TargetAttributes = {
|
||||
504EC3031FED79650016851F = {
|
||||
CreatedOnToolsVersion = 9.2;
|
||||
LastSwiftMigration = 1100;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */;
|
||||
compatibilityVersion = "Xcode 8.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 504EC2FB1FED79650016851F;
|
||||
productRefGroup = 504EC3051FED79650016851F /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
504EC3031FED79650016851F /* App */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
504EC3021FED79650016851F /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
504EC3121FED79650016851F /* LaunchScreen.storyboard in Resources */,
|
||||
50B271D11FEDC1A000F3C39B /* public in Resources */,
|
||||
504EC30F1FED79650016851F /* Assets.xcassets in Resources */,
|
||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */,
|
||||
504EC30D1FED79650016851F /* Main.storyboard in Resources */,
|
||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
0C3780443725062B779B937E /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
6634F4EFEBD30273BCE97C65 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-App-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9592DBEFFC6D2A0C8D5DEB22 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-App/Pods-App-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
504EC3001FED79650016851F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
504EC30B1FED79650016851F /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
504EC30C1FED79650016851F /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
504EC3101FED79650016851F /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
504EC3111FED79650016851F /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
504EC3141FED79650016851F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
504EC3151FED79650016851F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
504EC3171FED79650016851F /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 8C99SX84P9;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = de.anyschool.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
504EC3181FED79650016851F /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_TEAM = 8C99SX84P9;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = de.anyschool.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
504EC2FF1FED79650016851F /* Build configuration list for PBXProject "App" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
504EC3141FED79650016851F /* Debug */,
|
||||
504EC3151FED79650016851F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
504EC3161FED79650016851F /* Build configuration list for PBXNativeTarget "App" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
504EC3171FED79650016851F /* Debug */,
|
||||
504EC3181FED79650016851F /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 504EC2FC1FED79650016851F /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:App.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||
BuildableName = "App.app"
|
||||
BlueprintName = "App"
|
||||
ReferencedContainer = "container:App.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||
BuildableName = "App.app"
|
||||
BlueprintName = "App"
|
||||
ReferencedContainer = "container:App.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||
BuildableName = "App.app"
|
||||
BlueprintName = "App"
|
||||
ReferencedContainer = "container:App.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:App.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:mobile.app.uni-frankfurt.de</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,60 @@
|
||||
import UIKit
|
||||
import Capacitor
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
}
|
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) {
|
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||
}
|
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) {
|
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
|
||||
}
|
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) {
|
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) {
|
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||
}
|
||||
|
||||
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
|
||||
// Called when the app was launched with a url. Feel free to add additional processing here,
|
||||
// but if you want the App API to support tracking app url opens, make sure to keep this call
|
||||
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
|
||||
// Called when the app was launched with an activity, including Universal Links.
|
||||
// Feel free to add additional processing here, but if you want the App API to support
|
||||
// tracking app url opens, make sure to keep this call
|
||||
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
let statusBarRect = UIApplication.shared.statusBarFrame
|
||||
guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return }
|
||||
|
||||
if statusBarRect.contains(touchPoint) {
|
||||
NotificationCenter.default.post(name: .capacitorStatusBarTapped, object: nil)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "AppIcon-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-20x20@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-40x40@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "AppIcon-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-2.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="17132" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17105"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<imageView key="view" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="Splash" id="snD-IY-ifK">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
</imageView>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Splash" width="1366" height="1366"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
</resources>
|
||||
</document>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14111" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Bridge View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="CAPBridgeViewController" customModule="Capacitor" sceneMemberID="viewController"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>StApps</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>de.anyschool.app</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>de.anyschool.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict/>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"appId": "de.anyschool.app",
|
||||
"appName": "StApps",
|
||||
"webDir": "www",
|
||||
"bundledWebRuntime": false,
|
||||
"cordova": {
|
||||
"preferences": {
|
||||
"AndroidXEnabled": "true",
|
||||
"ScrollEnabled": "false",
|
||||
"android-minSdkVersion": "22",
|
||||
"BackupWebStorage": "none",
|
||||
"SplashMaintainAspectRatio": "true",
|
||||
"FadeSplashScreenDuration": "300",
|
||||
"SplashShowOnlyFirstTime": "false",
|
||||
"SplashScreen": "screen",
|
||||
"SplashScreenDelay": "3000"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<widget version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
|
||||
<access origin="*" />
|
||||
|
||||
<feature name="Device">
|
||||
<param name="ios-package" value="CDVDevice"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Notification">
|
||||
<param name="ios-package" value="CDVNotification"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Geolocation">
|
||||
<param name="ios-package" value="CDVLocation"/>
|
||||
</feature>
|
||||
|
||||
<feature name="NetworkStatus">
|
||||
<param name="ios-package" value="CDVConnection"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic">
|
||||
<param name="ios-package" value="Diagnostic"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Location">
|
||||
<param name="ios-package" value="Diagnostic_Location"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Bluetooth">
|
||||
<param name="ios-package" value="Diagnostic_Bluetooth"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Wifi">
|
||||
<param name="ios-package" value="Diagnostic_Wifi"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Camera">
|
||||
<param name="ios-package" value="Diagnostic_Camera"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Notifications">
|
||||
<param name="ios-package" value="Diagnostic_Notifications"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Microphone">
|
||||
<param name="ios-package" value="Diagnostic_Microphone"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Contacts">
|
||||
<param name="ios-package" value="Diagnostic_Contacts"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Calendar">
|
||||
<param name="ios-package" value="Diagnostic_Calendar"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Reminders">
|
||||
<param name="ios-package" value="Diagnostic_Reminders"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
<feature name="Diagnostic_Motion">
|
||||
<param name="ios-package" value="Diagnostic_Motion"/>
|
||||
<param name="onload" value="true"/>
|
||||
</feature>
|
||||
|
||||
|
||||
<preference name="AndroidXEnabled" value="true" />
|
||||
<preference name="ScrollEnabled" value="false" />
|
||||
<preference name="android-minSdkVersion" value="22" />
|
||||
<preference name="BackupWebStorage" value="none" />
|
||||
<preference name="SplashMaintainAspectRatio" value="true" />
|
||||
<preference name="FadeSplashScreenDuration" value="300" />
|
||||
<preference name="SplashShowOnlyFirstTime" value="false" />
|
||||
<preference name="SplashScreen" value="screen" />
|
||||
<preference name="SplashScreenDelay" value="3000" />
|
||||
</widget>
|
||||
@@ -0,0 +1,28 @@
|
||||
platform :ios, '12.0'
|
||||
use_frameworks!
|
||||
|
||||
# workaround to avoid Xcode caching of Pods that requires
|
||||
# Product -> Clean Build Folder after new Cordova plugins installed
|
||||
# Requires CocoaPods 1.6 or newer
|
||||
install! 'cocoapods', :disable_input_output_paths => true
|
||||
|
||||
def capacitor_pods
|
||||
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCommunityHttp', :path => '../../node_modules/@capacitor-community/http'
|
||||
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
|
||||
pod 'CapacitorBrowser', :path => '../../node_modules/@capacitor/browser'
|
||||
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
|
||||
pod 'CapacitorKeyboard', :path => '../../node_modules/@capacitor/keyboard'
|
||||
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
|
||||
pod 'CapacitorStatusBar', :path => '../../node_modules/@capacitor/status-bar'
|
||||
pod 'CapacitorStorage', :path => '../../node_modules/@capacitor/storage'
|
||||
pod 'CapacitorSecureStoragePlugin', :path => '../../node_modules/capacitor-secure-storage-plugin'
|
||||
pod 'CordovaPlugins', :path => '../capacitor-cordova-ios-plugins'
|
||||
pod 'CordovaPluginsResources', :path => '../capacitor-cordova-ios-plugins'
|
||||
end
|
||||
|
||||
target 'App' do
|
||||
capacitor_pods
|
||||
# Add your Pods here
|
||||
end
|
||||
Generated
+218
-20
@@ -2067,11 +2067,21 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@capacitor-community/http": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor-community/http/-/http-1.4.1.tgz",
|
||||
"integrity": "sha512-+pCkBXrwfm97UfjOgjV950H/qZ8SE36Mrcb46BlL1ps3VIsGuIO+AulL8GqTC6LewheRVtGJpRspNtneXQotNA==",
|
||||
"requires": {
|
||||
"@capacitor/android": "^3.0.0",
|
||||
"@capacitor/core": "^3.0.0",
|
||||
"@capacitor/filesystem": "^1.0.0",
|
||||
"@capacitor/ios": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"@capacitor/android": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.3.2.tgz",
|
||||
"integrity": "sha512-TG+tGz0KxkT/BgvSLQfbQwQ9c4Budub5TRijIGdmMbB1ZYB76TFhwvVuwWZ52HFSlKS3sx/UYLlbULL7UQ2aug==",
|
||||
"dev": true
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.4.0.tgz",
|
||||
"integrity": "sha512-O2hHGVzdTH2Lsmz58EI8zHY5byEFIWl9KrW60WSrO/tV6u9DpfaUq56FaejvfU27GFXDZkmoQNa33EvDYWp4wA=="
|
||||
},
|
||||
"@capacitor/app": {
|
||||
"version": "1.0.6",
|
||||
@@ -2152,6 +2162,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@capacitor/filesystem": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/filesystem/-/filesystem-1.1.0.tgz",
|
||||
"integrity": "sha512-8O3UuvL8HNUEJvZnmn8yUmvgB1evtXfcF0oxIo3YbSlylqywJwS3JTiuhKmsvSxCdpbTy8IaTsutVh3gZgWbKg=="
|
||||
},
|
||||
"@capacitor/haptics": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-1.1.3.tgz",
|
||||
@@ -2160,8 +2175,7 @@
|
||||
"@capacitor/ios": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.3.2.tgz",
|
||||
"integrity": "sha512-qXbWo9zTtinIYDxKsLdkXXuZD8H+wlJII3+ZF9QzH+38IYyd+sohOG3NLC8EaX7GRtwCymd+mGotoN420SfQ4Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-qXbWo9zTtinIYDxKsLdkXXuZD8H+wlJII3+ZF9QzH+38IYyd+sohOG3NLC8EaX7GRtwCymd+mGotoN420SfQ4Q=="
|
||||
},
|
||||
"@capacitor/keyboard": {
|
||||
"version": "1.1.3",
|
||||
@@ -2178,6 +2192,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-1.0.6.tgz",
|
||||
"integrity": "sha512-5MGWFq76iiKvHpbZ/Xc0Zig3WZyzWZ62wvC4qxak8OuVHBNG4fA1p/XXY9teQPaU3SupEJHnLkw6Gn1LuDp+ew=="
|
||||
},
|
||||
"@capacitor/storage": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/storage/-/storage-1.2.3.tgz",
|
||||
"integrity": "sha512-Rc5CKS53sfxokF5dxzNQDhig4lnZonky6VqskHZKTe3Ltl37FKmrG+I8ttZCinFZ5MPWfGSuP44m93hsQqitjQ=="
|
||||
},
|
||||
"@compodoc/compodoc": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@compodoc/compodoc/-/compodoc-1.1.14.tgz",
|
||||
@@ -2532,6 +2551,40 @@
|
||||
"@types/cordova": "^0.0.34"
|
||||
}
|
||||
},
|
||||
"@ionic-native/http": {
|
||||
"version": "5.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/http/-/http-5.35.0.tgz",
|
||||
"integrity": "sha512-AaLvi59gdOlxpM3x9krk0l8UcLI9OLBm+o7DNu8y1pgsUKIvf7+ZbY4xU1fJG1HDvUyrU8+NQLrvXgpXx6CmAQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/cordova": "^0.0.34"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/cordova": {
|
||||
"version": "0.0.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
|
||||
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ionic-native/in-app-browser": {
|
||||
"version": "5.36.0",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/in-app-browser/-/in-app-browser-5.36.0.tgz",
|
||||
"integrity": "sha512-tX/FBT0jpkgEefZ8iorv5eDKfgP/ExbYr1AWg6okORQ0dwLfXsD5KDJgKHN9GFZvyuLNeaLpC1mN7CvwvLvmgA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/cordova": "^0.0.34"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/cordova": {
|
||||
"version": "0.0.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
|
||||
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ionic-native/network": {
|
||||
"version": "5.36.0",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/network/-/network-5.36.0.tgz",
|
||||
@@ -2540,6 +2593,40 @@
|
||||
"@types/cordova": "^0.0.34"
|
||||
}
|
||||
},
|
||||
"@ionic-native/safari-view-controller": {
|
||||
"version": "5.36.0",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/safari-view-controller/-/safari-view-controller-5.36.0.tgz",
|
||||
"integrity": "sha512-pvqnzro3bBZ0bQOMjBRKhmjHDaLKfDS75QY7uqe9UzjufMnHtBUUWgMvTuL7MsjTXRj8iRhe1wnUv8aBkz4SVA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/cordova": "^0.0.34"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/cordova": {
|
||||
"version": "0.0.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
|
||||
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ionic-native/secure-storage": {
|
||||
"version": "5.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@ionic-native/secure-storage/-/secure-storage-5.35.0.tgz",
|
||||
"integrity": "sha512-QJSMGsvYOFWX95zMbCMMfNdtOnx9su6GKPmw6p+lLYWTXa5bqqRMSRtPInQmv1dz6GCcAMdXbUGADjBgwQQsaA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"@types/cordova": "^0.0.34"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/cordova": {
|
||||
"version": "0.0.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz",
|
||||
"integrity": "sha1-6nrd907Ow9dimCegw54smt3HPQQ=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ionic/angular": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-5.7.0.tgz",
|
||||
@@ -3216,6 +3303,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@openid/appauth": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@openid/appauth/-/appauth-1.3.1.tgz",
|
||||
"integrity": "sha512-e54kpi219wES2ijPzeHe1kMnT8VKH8YeTd1GAn9BzVBmutz3tBgcG1y8a4pziNr4vNjFnuD4W446Ua7ELnNDiA==",
|
||||
"requires": {
|
||||
"@types/base64-js": "^1.3.0",
|
||||
"@types/jquery": "^3.5.5",
|
||||
"base64-js": "^1.5.1",
|
||||
"follow-redirects": "^1.13.3",
|
||||
"form-data": "^4.0.0",
|
||||
"opener": "^1.5.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"form-data": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@openstapps/api": {
|
||||
"version": "0.35.0",
|
||||
"resolved": "https://registry.npmjs.org/@openstapps/api/-/api-0.35.0.tgz",
|
||||
@@ -3504,6 +3616,11 @@
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
|
||||
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA=="
|
||||
},
|
||||
"@types/base64-js": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/base64-js/-/base64-js-1.3.0.tgz",
|
||||
"integrity": "sha512-ZmI0sZGAUNXUfMWboWwi4LcfpoVUYldyN6Oe0oJ5cCsHDU/LlRq8nQKPXhYLOx36QYSW9bNIb1vvRrD6K7Llgw=="
|
||||
},
|
||||
"@types/body-parser": {
|
||||
"version": "1.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
||||
@@ -3698,6 +3815,14 @@
|
||||
"@types/jasmine": "*"
|
||||
}
|
||||
},
|
||||
"@types/jquery": {
|
||||
"version": "3.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.8.tgz",
|
||||
"integrity": "sha512-cXk6NwqjDYg+UI9p2l3x0YmPa4m7RrXqmbK4IpVVpRJiYXU/QTo+UZrn54qfE1+9Gao4qpYqUnxm5ZCy2FTXAw==",
|
||||
"requires": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"@types/json-patch": {
|
||||
"version": "0.0.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-patch/-/json-patch-0.0.30.tgz",
|
||||
@@ -3884,6 +4009,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@types/sizzle": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
|
||||
"integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ=="
|
||||
},
|
||||
"@types/source-list-map": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||
@@ -5108,8 +5238,7 @@
|
||||
"base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||
},
|
||||
"base64id": {
|
||||
"version": "2.0.0",
|
||||
@@ -5315,6 +5444,11 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5638,7 +5772,6 @@
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
@@ -5704,6 +5837,14 @@
|
||||
"integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
|
||||
"dev": true
|
||||
},
|
||||
"capacitor-secure-storage-plugin": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/capacitor-secure-storage-plugin/-/capacitor-secure-storage-plugin-0.6.2.tgz",
|
||||
"integrity": "sha512-f05BLb98TG5qqxN8FvTOLPNvtoebdZyrWAueoyw25Xip7nJBkFqrGxZtcFDMONi4DZRz/z9DMz1Bw8F/8fPAJA==",
|
||||
"requires": {
|
||||
"@capacitor/core": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
@@ -8770,6 +8911,11 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9298,7 +9444,6 @@
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
||||
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
@@ -9579,6 +9724,11 @@
|
||||
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
|
||||
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
|
||||
},
|
||||
"guid-typescript": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
|
||||
"integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ=="
|
||||
},
|
||||
"handle-thing": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||
@@ -9661,8 +9811,7 @@
|
||||
"has-symbols": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
|
||||
},
|
||||
"has-tostringtag": {
|
||||
"version": "1.0.0",
|
||||
@@ -10307,6 +10456,33 @@
|
||||
"ipaddr.js": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"ionic-appauth": {
|
||||
"version": "0.8.5",
|
||||
"resolved": "https://registry.npmjs.org/ionic-appauth/-/ionic-appauth-0.8.5.tgz",
|
||||
"integrity": "sha512-4GyFasdqLboGz4mej71UcsSM7XodpFXOcBYdtGvUKJ29p0iIB3/c5BHuGAmpiTqvUfAnGD8insimaQEE3Iensw==",
|
||||
"requires": {
|
||||
"@capacitor/browser": "^1.0.2",
|
||||
"@capacitor/core": "^3.1.2",
|
||||
"@capacitor/storage": "^1.0.3",
|
||||
"@ionic-native/core": "^5.34.0",
|
||||
"@ionic-native/http": "^5.34.0",
|
||||
"@ionic-native/in-app-browser": "^5.34.0",
|
||||
"@ionic-native/safari-view-controller": "^5.34.0",
|
||||
"@ionic-native/secure-storage": "^5.34.0",
|
||||
"@ionic/storage": "^3.0.6",
|
||||
"@openid/appauth": "^1.3.1",
|
||||
"capacitor-secure-storage-plugin": "^0.6.2",
|
||||
"guid-typescript": "^1.0.9",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ionicons": {
|
||||
"version": "5.5.4",
|
||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.4.tgz",
|
||||
@@ -11069,6 +11245,11 @@
|
||||
"integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
|
||||
"dev": true
|
||||
},
|
||||
"jsonpath-plus": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz",
|
||||
"integrity": "sha512-EvGovdvau6FyLexFH2OeXfIITlgIbgZoAZe3usiySeaIDm5QS+A10DKNpaPBBqqRSZr2HN6HVNXxtwUAr2apEw=="
|
||||
},
|
||||
"jsonpointer": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz",
|
||||
@@ -12882,8 +13063,7 @@
|
||||
"object-inspect": {
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
|
||||
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
|
||||
},
|
||||
"object-is": {
|
||||
"version": "1.1.5",
|
||||
@@ -12997,6 +13177,11 @@
|
||||
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"opener": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
|
||||
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="
|
||||
},
|
||||
"opening_hours": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/opening_hours/-/opening_hours-3.7.0.tgz",
|
||||
@@ -15413,9 +15598,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"qs": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||
"version": "6.10.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
|
||||
"integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
|
||||
"requires": {
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
@@ -16147,9 +16335,9 @@
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "6.6.3",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
|
||||
"integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
|
||||
"version": "6.6.7",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
|
||||
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
|
||||
"requires": {
|
||||
"tslib": "^1.9.0"
|
||||
},
|
||||
@@ -16547,6 +16735,16 @@
|
||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
|
||||
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
|
||||
|
||||
+9
-2
@@ -54,6 +54,7 @@
|
||||
"@angular/router": "12.2.13",
|
||||
"@asymmetrik/ngx-leaflet": "8.1.0",
|
||||
"@asymmetrik/ngx-leaflet-markercluster": "5.0.1",
|
||||
"@capacitor-community/http": "1.4.1",
|
||||
"@capacitor/app": "1.0.6",
|
||||
"@capacitor/browser": "1.0.6",
|
||||
"@capacitor/core": "3.3.1",
|
||||
@@ -61,6 +62,7 @@
|
||||
"@capacitor/keyboard": "1.1.3",
|
||||
"@capacitor/splash-screen": "1.1.6",
|
||||
"@capacitor/status-bar": "1.0.6",
|
||||
"@capacitor/storage": "1.2.3",
|
||||
"@ionic-native/core": "5.36.0",
|
||||
"@ionic-native/diagnostic": "5.36.0",
|
||||
"@ionic-native/dialogs": "5.36.0",
|
||||
@@ -73,6 +75,7 @@
|
||||
"@openstapps/api": "0.35.0",
|
||||
"@openstapps/configuration": "0.28.1",
|
||||
"@openstapps/core": "0.53.0",
|
||||
"capacitor-secure-storage-plugin": "0.6.2",
|
||||
"cordova-plugin-device": "2.0.3",
|
||||
"cordova-plugin-dialogs": "2.0.2",
|
||||
"cordova-plugin-geolocation": "4.1.0",
|
||||
@@ -83,6 +86,8 @@
|
||||
"deepmerge": "3.3.0",
|
||||
"form-data": "2.5.0",
|
||||
"geojson": "0.5.0",
|
||||
"ionic-appauth": "0.8.5",
|
||||
"jsonpath-plus": "6.0.1",
|
||||
"leaflet": "1.7.1",
|
||||
"leaflet.markercluster": "1.5.1",
|
||||
"lodash-es": "4.17.21",
|
||||
@@ -91,7 +96,8 @@
|
||||
"ngx-markdown": "12.0.1",
|
||||
"ngx-moment": "5.0.0",
|
||||
"opening_hours": "3.7.0",
|
||||
"rxjs": "6.6.3",
|
||||
"qs": "6.10.1",
|
||||
"rxjs": "6.6.7",
|
||||
"swiper": "7.1.0",
|
||||
"tslib": "2.0.0",
|
||||
"zone.js": "0.11.4"
|
||||
@@ -110,7 +116,7 @@
|
||||
"@angular/compiler": "12.2.13",
|
||||
"@angular/compiler-cli": "12.2.13",
|
||||
"@angular/language-service": "12.2.13",
|
||||
"@capacitor/android": "3.3.2",
|
||||
"@capacitor/android": "3.4.0",
|
||||
"@capacitor/cli": "3.3.2",
|
||||
"@capacitor/ios": "3.3.2",
|
||||
"@compodoc/compodoc": "1.1.14",
|
||||
@@ -123,6 +129,7 @@
|
||||
"@types/leaflet.markercluster": "1.4.5",
|
||||
"@types/lodash-es": "4.17.4",
|
||||
"@types/node": "14.17.16",
|
||||
"@types/qs": "6.9.7",
|
||||
"@typescript-eslint/eslint-plugin": "4.32.0",
|
||||
"@typescript-eslint/parser": "4.32.0",
|
||||
"conventional-changelog-cli": "2.1.1",
|
||||
|
||||
@@ -30478,7 +30478,7 @@ export const sampleResources = [{
|
||||
'steps': [
|
||||
{
|
||||
'type': 'location',
|
||||
'location': '#/b-tu/main'
|
||||
'location': '/b-tu/main'
|
||||
},
|
||||
{
|
||||
'type': 'tooltip',
|
||||
@@ -30494,7 +30494,7 @@ export const sampleResources = [{
|
||||
'text': 'Öffne die Suche.',
|
||||
'resolved': {
|
||||
'location': {
|
||||
'is': '#/b-tu/search'
|
||||
'is': '/b-tu/search'
|
||||
}
|
||||
},
|
||||
'position': 'bottom'
|
||||
@@ -30529,7 +30529,7 @@ export const sampleResources = [{
|
||||
'text': 'Klicke auf eine Veranstaltung...',
|
||||
'resolved': {
|
||||
'location': {
|
||||
'match': '#/b-tu/data/detail/Event'
|
||||
'match': '/b-tu/data/detail/Event'
|
||||
}
|
||||
},
|
||||
'position': 'top'
|
||||
@@ -30553,7 +30553,7 @@ export const sampleResources = [{
|
||||
'text': 'Öffne deinen Stundenplan.',
|
||||
'resolved': {
|
||||
'location': {
|
||||
'is': '#/b-tu/events'
|
||||
'is': '/b-tu/events'
|
||||
}
|
||||
},
|
||||
'position': 'right'
|
||||
@@ -30585,7 +30585,7 @@ export const sampleResources = [{
|
||||
'steps': [
|
||||
{
|
||||
'type': 'location',
|
||||
'location': '#/b-tu/main'
|
||||
'location': '/b-tu/main'
|
||||
},
|
||||
{
|
||||
'type': 'tooltip',
|
||||
@@ -30632,7 +30632,7 @@ export const sampleResources = [{
|
||||
'text': 'Das ist das Widget, dass dir die Speisepläne deiner favorisierten Essensorte anzeigt. Klicke auf "Essensorte", um zur Übersicht der Essensorte zu gelangen.',
|
||||
'resolved': {
|
||||
'location': {
|
||||
'is': '#/b-tu/places?types=FoodEstablishment'
|
||||
'is': '/b-tu/places?types=FoodEstablishment'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -30642,7 +30642,7 @@ export const sampleResources = [{
|
||||
'text': 'Wähle die "Mathe Cafeteria" aus, um sie zu favorisieren.',
|
||||
'resolved': {
|
||||
'location': {
|
||||
'is': '#/b-tu/map?place=MA%20Mathe%20Cafeteria'
|
||||
'is': '/b-tu/map?place=MA%20Mathe%20Cafeteria'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -30668,7 +30668,7 @@ export const sampleResources = [{
|
||||
'text': 'Klicke auf das TU-Logo oder "StApps", um zur Startseite zurückzukehren.',
|
||||
'resolved': {
|
||||
'location': {
|
||||
'is': '#/b-tu/main'
|
||||
'is': '/b-tu/main'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -30691,7 +30691,7 @@ export const sampleResources = [{
|
||||
'text': 'Öffne deine Favoriten.',
|
||||
'resolved': {
|
||||
'location': {
|
||||
'is': '#/b-tu/favorites'
|
||||
'is': '/b-tu/favorites'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {PreloadAllModules, RouterModule, Routes} from '@angular/router';
|
||||
|
||||
const routes: Routes = [{path: '', redirectTo: '/news', pathMatch: 'full'}];
|
||||
|
||||
@@ -22,6 +22,11 @@ const routes: Routes = [{path: '', redirectTo: '/news', pathMatch: 'full'}];
|
||||
*/
|
||||
@NgModule({
|
||||
exports: [RouterModule],
|
||||
imports: [RouterModule.forRoot(routes, {relativeLinkResolution: 'legacy'})],
|
||||
imports: [
|
||||
RouterModule.forRoot(routes, {
|
||||
enableTracing: true,
|
||||
preloadingStrategy: PreloadAllModules,
|
||||
}),
|
||||
],
|
||||
})
|
||||
export class AppRoutingModule {}
|
||||
|
||||
@@ -20,7 +20,9 @@ import {Platform} from '@ionic/angular';
|
||||
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {ThingTranslateService} from './translation/thing-translate.service';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {AppComponent} from './app.component';
|
||||
import {AuthModule} from './modules/auth/auth.module';
|
||||
import {ConfigProvider} from './modules/config/config.provider';
|
||||
import {SettingsProvider} from './modules/settings/settings.provider';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
@@ -35,10 +37,16 @@ describe('AppComponent', () => {
|
||||
let configProvider: jasmine.SpyObj<ConfigProvider>;
|
||||
let ngxLogger: jasmine.SpyObj<NGXLogger>;
|
||||
|
||||
let platformIsSpy;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
platformReadySpy = Promise.resolve();
|
||||
platformSpy = jasmine.createSpyObj('Platform', {ready: platformReadySpy});
|
||||
platformIsSpy = Promise.resolve();
|
||||
platformSpy = jasmine.createSpyObj('Platform', {
|
||||
ready: platformReadySpy,
|
||||
is: platformIsSpy,
|
||||
});
|
||||
translateServiceSpy = jasmine.createSpyObj('TranslateService', [
|
||||
'setDefaultLang',
|
||||
'use',
|
||||
@@ -55,7 +63,11 @@ describe('AppComponent', () => {
|
||||
ngxLogger = jasmine.createSpyObj('NGXLogger', ['log', 'error', 'warn']);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule.withRoutes([])],
|
||||
imports: [
|
||||
RouterTestingModule.withRoutes([]),
|
||||
HttpClientTestingModule,
|
||||
AuthModule,
|
||||
],
|
||||
declarations: [AppComponent],
|
||||
providers: [
|
||||
{provide: Platform, useValue: platformSpy},
|
||||
|
||||
@@ -16,10 +16,14 @@ import {Component, NgZone} from '@angular/core';
|
||||
import {Router} from '@angular/router';
|
||||
import {App, URLOpenListenerEvent} from '@capacitor/app';
|
||||
import {SplashScreen} from '@capacitor/splash-screen';
|
||||
import {Platform} from '@ionic/angular';
|
||||
import {Platform, ToastController} from '@ionic/angular';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
import {ConfigProvider} from './modules/config/config.provider';
|
||||
import {SettingsProvider} from './modules/settings/settings.provider';
|
||||
import {PAIAAuthService} from './modules/auth/paia/paia-auth.service';
|
||||
import {DefaultAuthService} from './modules/auth/default-auth.service';
|
||||
import {environment} from '../environments/environment';
|
||||
import {AuthHelperService} from './modules/auth/auth-helper.service';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
@@ -51,6 +55,10 @@ export class AppComponent {
|
||||
* @param logger An angular logger
|
||||
* @param router The angular router
|
||||
* @param zone The angular zone
|
||||
* @param defaultAuth Auth Service
|
||||
* @param paiaAuth Auth Service
|
||||
* @param authHelperService Helper service for OAuth providers
|
||||
* @param toastController Toast controller
|
||||
*/
|
||||
constructor(
|
||||
private readonly platform: Platform,
|
||||
@@ -59,6 +67,10 @@ export class AppComponent {
|
||||
private readonly logger: NGXLogger,
|
||||
private readonly router: Router,
|
||||
private readonly zone: NgZone,
|
||||
private readonly defaultAuth: DefaultAuthService,
|
||||
private readonly paiaAuth: PAIAAuthService,
|
||||
private readonly authHelperService: AuthHelperService,
|
||||
private readonly toastController: ToastController,
|
||||
) {
|
||||
void this.initializeApp();
|
||||
}
|
||||
@@ -69,7 +81,7 @@ export class AppComponent {
|
||||
async initializeApp() {
|
||||
App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {
|
||||
this.zone.run(() => {
|
||||
const slug = event.url.split('.de').pop();
|
||||
const slug = event.url.split(environment.appDomain).pop();
|
||||
if (slug) {
|
||||
this.router.navigateByUrl(slug);
|
||||
}
|
||||
@@ -78,6 +90,9 @@ export class AppComponent {
|
||||
});
|
||||
});
|
||||
this.platform.ready().then(async () => {
|
||||
await this.authInit();
|
||||
await this.defaultAuth.init();
|
||||
await this.paiaAuth.init();
|
||||
await SplashScreen.hide();
|
||||
|
||||
// initialise the configProvider
|
||||
@@ -102,4 +117,28 @@ export class AppComponent {
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
private async authInit() {
|
||||
await this.defaultAuth.init();
|
||||
await this.paiaAuth.init();
|
||||
this.defaultAuth.events$.subscribe(action =>
|
||||
this.showMessage(
|
||||
this.authHelperService.getAuthMessage('default', action),
|
||||
),
|
||||
);
|
||||
this.paiaAuth.events$.subscribe(action =>
|
||||
this.showMessage(this.authHelperService.getAuthMessage('paia', action)),
|
||||
);
|
||||
}
|
||||
|
||||
private async showMessage(message?: string) {
|
||||
if (typeof message === 'undefined') {
|
||||
return;
|
||||
}
|
||||
const toast = await this.toastController.create({
|
||||
message: message,
|
||||
duration: 2000,
|
||||
});
|
||||
await toast.present();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
PathLocationStrategy,
|
||||
registerLocaleData,
|
||||
} from '@angular/common';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||
import localeDe from '@angular/common/locales/de';
|
||||
import {APP_INITIALIZER, NgModule, Provider} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
@@ -55,10 +55,13 @@ import {initLogger} from './_helpers/ts-logger';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {AboutModule} from './modules/about/about.module';
|
||||
import {FavoritesModule} from './modules/favorites/favorites.module';
|
||||
import {ProfilePageModule} from './modules/profile/profile.module';
|
||||
import {EndSessionPageModule} from './modules/auth/end-session/end-session.module';
|
||||
import {FeedbackModule} from './modules/feedback/feedback.module';
|
||||
import {DebugDataCollectorService} from './modules/data/debug-data-collector.service';
|
||||
import {Browser} from './util/browser.factory';
|
||||
import {browserFactory} from './util/browser.factory';
|
||||
import {AuthModule} from './modules/auth/auth.module';
|
||||
|
||||
registerLocaleData(localeDe);
|
||||
|
||||
@@ -143,14 +146,18 @@ const providers: Provider[] = [
|
||||
imports: [
|
||||
AboutModule,
|
||||
AppRoutingModule,
|
||||
AuthModule,
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
CatalogModule,
|
||||
CommonModule,
|
||||
ConfigModule,
|
||||
DataModule,
|
||||
EndSessionPageModule,
|
||||
IonicModule.forRoot(),
|
||||
FavoritesModule,
|
||||
HttpClientModule,
|
||||
ProfilePageModule,
|
||||
FeedbackModule,
|
||||
MapModule,
|
||||
MenuModule,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="centeredMessageContainer">
|
||||
<p>{{ 'auth.messages.default.authorizing' | translate }}</p>
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
import {Component, OnInit, OnDestroy} from '@angular/core';
|
||||
import {NavController} from '@ionic/angular';
|
||||
import {Router} from '@angular/router';
|
||||
import {IAuthAction} from 'ionic-appauth';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {DefaultAuthService} from '../../default-auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'auth-callback',
|
||||
templateUrl: './auth-callback-page.component.html',
|
||||
styleUrls: ['./auth-callback-page.component.scss'],
|
||||
})
|
||||
export class AuthCallbackPageComponent implements OnInit, OnDestroy {
|
||||
sub: Subscription;
|
||||
|
||||
constructor(
|
||||
private auth: DefaultAuthService,
|
||||
private navCtrl: NavController,
|
||||
private router: Router,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.sub = this.auth.events$.subscribe(action => this.postCallback(action));
|
||||
this.auth.authorizationCallback(window.location.origin + this.router.url);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
async postCallback(_action: IAuthAction) {
|
||||
await this.navCtrl.navigateRoot('profile');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {CanActivate, Router, RouterStateSnapshot} from '@angular/router';
|
||||
import {DefaultAuthService} from './default-auth.service';
|
||||
import {PAIAAuthService} from './paia/paia-auth.service';
|
||||
import {IAuthService} from 'ionic-appauth';
|
||||
import {ActivatedAuthRouteSnapshot} from './auth-routes';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthGuardService implements CanActivate {
|
||||
authService: IAuthService | PAIAAuthService;
|
||||
|
||||
constructor(
|
||||
private defaultAuth: DefaultAuthService,
|
||||
private paiaAuth: PAIAAuthService,
|
||||
private router: Router,
|
||||
) {}
|
||||
|
||||
public async canActivate(
|
||||
route: ActivatedAuthRouteSnapshot,
|
||||
_state: RouterStateSnapshot,
|
||||
) {
|
||||
switch (route.data.authProvider) {
|
||||
case 'paia':
|
||||
this.authService = this.paiaAuth;
|
||||
break;
|
||||
default:
|
||||
this.authService = this.defaultAuth;
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.authService.getValidToken();
|
||||
} catch {
|
||||
this.router.navigate(['profile']);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {
|
||||
SCAuthorizationProviderType,
|
||||
SCUserConfiguration,
|
||||
userMapping,
|
||||
} from '../profile/user';
|
||||
import {IPAIAAuthAction} from './paia/paia-auth-action';
|
||||
import {AuthActions, IAuthAction} from 'ionic-appauth';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {JSONFile} from '@angular/cli/utilities/json-file';
|
||||
import {JSONPath} from 'jsonpath-plus';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthHelperService {
|
||||
constructor(private translateService: TranslateService) {}
|
||||
|
||||
public getAuthMessage(
|
||||
provider: SCAuthorizationProviderType,
|
||||
action: IAuthAction | IPAIAAuthAction,
|
||||
) {
|
||||
let message: string | undefined;
|
||||
switch (action.action) {
|
||||
case AuthActions.SignInSuccess:
|
||||
message = this.translateService.instant(
|
||||
`auth.messages.${provider}.logged_in_success`,
|
||||
);
|
||||
break;
|
||||
case AuthActions.SignOutSuccess:
|
||||
message = this.translateService.instant(
|
||||
`auth.messages.${provider}.logged_out_success`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
getUserFromUserInfo(userInfo: JSONFile) {
|
||||
const user: SCUserConfiguration = {id: '', name: '', role: 'student'};
|
||||
for (const key in userMapping) {
|
||||
user[key as keyof SCUserConfiguration] = JSONPath({
|
||||
path: userMapping[key as keyof SCUserConfiguration] as string,
|
||||
json: userInfo,
|
||||
})[0];
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {ActivatedRouteSnapshot, Data, Route} from '@angular/router';
|
||||
import {SCAuthorizationProviderType} from '../profile/user';
|
||||
|
||||
export interface AuthRoute extends Route {
|
||||
data: {
|
||||
authProvider: SCAuthorizationProviderType;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export class ActivatedAuthRouteSnapshot extends ActivatedRouteSnapshot {
|
||||
data: Data & {authProvider: AuthRoute['data']['authProvider']};
|
||||
}
|
||||
|
||||
export type AuthRoutes = AuthRoute[];
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {AuthCallbackPageComponent} from './auth-callback/page/auth-callback-page.component';
|
||||
import {PAIAAuthCallbackPageComponent} from './paia/auth-callback/page/auth-callback-page.component';
|
||||
|
||||
const authRoutes: Routes = [
|
||||
{path: 'auth/callback', component: AuthCallbackPageComponent},
|
||||
{path: 'auth/paia/callback', component: PAIAAuthCallbackPageComponent},
|
||||
];
|
||||
|
||||
/**
|
||||
* Module defining routes for auth module
|
||||
*/
|
||||
@NgModule({
|
||||
exports: [RouterModule],
|
||||
imports: [RouterModule.forChild(authRoutes)],
|
||||
})
|
||||
export class AuthRoutingModule {}
|
||||
@@ -0,0 +1,47 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Platform} from '@ionic/angular';
|
||||
import {Requestor, StorageBackend} from '@openid/appauth';
|
||||
import {authFactory, paiaAuthFactory, storageFactory} from './factories';
|
||||
import {DefaultAuthService} from './default-auth.service';
|
||||
import {Browser} from 'ionic-appauth';
|
||||
import {CapacitorBrowser} from 'ionic-appauth/lib/capacitor';
|
||||
import {httpFactory} from './factories/http.factory';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {PAIAAuthService} from './paia/paia-auth.service';
|
||||
import {AuthRoutingModule} from './auth-routing.module';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {AuthCallbackPageComponent} from './auth-callback/page/auth-callback-page.component';
|
||||
import {PAIAAuthCallbackPageComponent} from './paia/auth-callback/page/auth-callback-page.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AuthCallbackPageComponent, PAIAAuthCallbackPageComponent],
|
||||
imports: [CommonModule, AuthRoutingModule, TranslateModule],
|
||||
providers: [
|
||||
{
|
||||
provide: StorageBackend,
|
||||
useFactory: storageFactory,
|
||||
deps: [Platform],
|
||||
},
|
||||
{
|
||||
provide: Requestor,
|
||||
useFactory: httpFactory,
|
||||
deps: [Platform, HttpClient],
|
||||
},
|
||||
{
|
||||
provide: Browser,
|
||||
useClass: CapacitorBrowser,
|
||||
},
|
||||
{
|
||||
provide: DefaultAuthService,
|
||||
useFactory: authFactory,
|
||||
deps: [Requestor, Browser, StorageBackend],
|
||||
},
|
||||
{
|
||||
provide: PAIAAuthService,
|
||||
useFactory: paiaAuthFactory,
|
||||
deps: [Requestor, Browser, StorageBackend],
|
||||
},
|
||||
],
|
||||
})
|
||||
export class AuthModule {}
|
||||
@@ -0,0 +1,53 @@
|
||||
import {Requestor} from '@openid/appauth';
|
||||
import {Http, HttpHeaders, HttpResponse} from '@capacitor-community/http';
|
||||
import {XhrSettings} from 'ionic-appauth/lib/cordova';
|
||||
import qs from 'qs';
|
||||
|
||||
// REQUIRES CAPACITOR PLUGIN
|
||||
// @capacitor-community/http
|
||||
export class CapacitorRequestor extends Requestor {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public async xhr<T>(settings: XhrSettings): Promise<T> {
|
||||
if (!settings.method) settings.method = 'GET';
|
||||
|
||||
switch (settings.method) {
|
||||
case 'GET':
|
||||
return this.get(settings.url, settings.headers);
|
||||
case 'POST':
|
||||
return this.post(settings.url, settings.data, settings.headers);
|
||||
case 'PUT':
|
||||
return this.put(settings.url, settings.data, settings.headers);
|
||||
case 'DELETE':
|
||||
return this.delete(settings.url, settings.headers);
|
||||
}
|
||||
}
|
||||
|
||||
private async get<T>(url: string, headers: HttpHeaders) {
|
||||
return Http.get({url, headers}).then(
|
||||
(response: HttpResponse) => response.data as T,
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private async post<T>(url: string, data: any, headers: HttpHeaders) {
|
||||
return Http.post({url, data: qs.parse(data), headers}).then(
|
||||
(response: HttpResponse) => response.data as T,
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private async put<T>(url: string, data: any, headers: HttpHeaders) {
|
||||
return Http.put({url, data, headers}).then(
|
||||
(response: HttpResponse) => response.data as T,
|
||||
);
|
||||
}
|
||||
|
||||
private async delete<T>(url: string, headers: HttpHeaders) {
|
||||
return Http.del({url, headers}).then(
|
||||
(response: HttpResponse) => response.data as T,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import {AuthorizationRequestHandler} from '@openid/appauth';
|
||||
import {
|
||||
StorageBackend,
|
||||
Requestor,
|
||||
AuthorizationServiceConfiguration,
|
||||
LocalStorageBackend,
|
||||
JQueryRequestor,
|
||||
TokenRequestHandler,
|
||||
} from '@openid/appauth';
|
||||
import {
|
||||
UserInfoHandler,
|
||||
EndSessionHandler,
|
||||
Browser,
|
||||
DefaultBrowser,
|
||||
AuthService,
|
||||
AuthActionBuilder,
|
||||
} from 'ionic-appauth';
|
||||
|
||||
const TOKEN_RESPONSE_KEY = 'token_response';
|
||||
|
||||
export class DefaultAuthService extends AuthService {
|
||||
public localConfiguration: AuthorizationServiceConfiguration;
|
||||
|
||||
protected tokenHandler: TokenRequestHandler;
|
||||
|
||||
protected userInfoHandler: UserInfoHandler;
|
||||
|
||||
protected requestHandler: AuthorizationRequestHandler;
|
||||
|
||||
protected endSessionHandler: EndSessionHandler;
|
||||
|
||||
constructor(
|
||||
protected browser: Browser = new DefaultBrowser(),
|
||||
protected storage: StorageBackend = new LocalStorageBackend(),
|
||||
protected requestor: Requestor = new JQueryRequestor(),
|
||||
) {
|
||||
super(browser, storage, requestor);
|
||||
}
|
||||
|
||||
get configuration(): Promise<AuthorizationServiceConfiguration> {
|
||||
if (!this.localConfiguration)
|
||||
throw new Error('Local Configuration Not Defined');
|
||||
|
||||
return Promise.resolve(this.localConfiguration);
|
||||
}
|
||||
|
||||
public async signOut() {
|
||||
await this.storage.removeItem(TOKEN_RESPONSE_KEY).catch(error => {
|
||||
this.notifyActionListers(AuthActionBuilder.SignOutFailed(error));
|
||||
});
|
||||
this.notifyActionListers(AuthActionBuilder.SignOutSuccess());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
|
||||
import {IonicModule} from '@ionic/angular';
|
||||
|
||||
import {EndSessionPageComponent} from './page/end-session-page.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'logout',
|
||||
component: EndSessionPageComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
RouterModule.forChild(routes),
|
||||
],
|
||||
declarations: [EndSessionPageComponent],
|
||||
})
|
||||
export class EndSessionPageModule {}
|
||||
@@ -0,0 +1 @@
|
||||
<p>Signing out...</p>
|
||||
@@ -0,0 +1,20 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {NavController} from '@ionic/angular';
|
||||
import {DefaultAuthService} from '../../default-auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'end-session',
|
||||
templateUrl: './end-session-page.component.html',
|
||||
styleUrls: ['./end-session-page.component.scss'],
|
||||
})
|
||||
export class EndSessionPageComponent implements OnInit {
|
||||
constructor(
|
||||
private auth: DefaultAuthService,
|
||||
private navCtrl: NavController,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.auth.endSessionCallback();
|
||||
await this.navCtrl.navigateRoot('profile');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
StorageBackend,
|
||||
Requestor,
|
||||
AuthorizationServiceConfiguration,
|
||||
} from '@openid/appauth';
|
||||
import {Browser} from 'ionic-appauth';
|
||||
import {environment} from 'src/environments/environment';
|
||||
import {DefaultAuthService} from '../default-auth.service';
|
||||
import {PAIAAuthService} from '../paia/paia-auth.service';
|
||||
|
||||
export const authFactory = (
|
||||
requestor: Requestor,
|
||||
browser: Browser,
|
||||
storage: StorageBackend,
|
||||
) => {
|
||||
const authService = new DefaultAuthService(browser, storage, requestor);
|
||||
authService.authConfig = environment.oauth2.client.his;
|
||||
authService.localConfiguration = new AuthorizationServiceConfiguration(
|
||||
environment.oauth2.service.his,
|
||||
);
|
||||
|
||||
return authService;
|
||||
};
|
||||
|
||||
export const paiaAuthFactory = (
|
||||
requestor: Requestor,
|
||||
browser: Browser,
|
||||
storage: StorageBackend,
|
||||
) => {
|
||||
const authService = new PAIAAuthService(browser, storage, requestor);
|
||||
authService.authConfig = environment.oauth2.client.paia;
|
||||
authService.localConfiguration = new AuthorizationServiceConfiguration(
|
||||
environment.oauth2.service.paia,
|
||||
);
|
||||
|
||||
return authService;
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
import {Platform} from '@ionic/angular';
|
||||
import {DefaultBrowser} from 'ionic-appauth';
|
||||
import {CapacitorBrowser} from 'ionic-appauth/lib/capacitor';
|
||||
|
||||
export const browserFactory = (platform: Platform) => {
|
||||
return platform.is('capacitor')
|
||||
? new CapacitorBrowser()
|
||||
: new DefaultBrowser();
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {Platform} from '@ionic/angular';
|
||||
import {CapacitorRequestor} from '../capacitor-requestor';
|
||||
import {NgHttpService} from '../ng-http.service';
|
||||
|
||||
export const httpFactory = (platform: Platform, httpClient: HttpClient) => {
|
||||
return platform.is('capacitor')
|
||||
? new CapacitorRequestor()
|
||||
: new NgHttpService(httpClient);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './auth.factory';
|
||||
export * from './browser.factory';
|
||||
export * from './storage.factory';
|
||||
@@ -0,0 +1,9 @@
|
||||
import {Platform} from '@ionic/angular';
|
||||
import {CapacitorSecureStorage} from 'ionic-appauth/lib/capacitor';
|
||||
import {IonicStorage} from 'ionic-appauth/lib';
|
||||
|
||||
export const storageFactory = (platform: Platform) => {
|
||||
return platform.is('capacitor')
|
||||
? new CapacitorSecureStorage()
|
||||
: new IonicStorage();
|
||||
};
|
||||
@@ -0,0 +1,53 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Requestor} from '@openid/appauth';
|
||||
import {HttpClient, HttpHeaders} from '@angular/common/http';
|
||||
import {XhrSettings} from 'ionic-appauth/lib/cordova';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class NgHttpService implements Requestor {
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
public async xhr<T>(settings: XhrSettings): Promise<T> {
|
||||
if (!settings.method) {
|
||||
settings.method = 'GET';
|
||||
}
|
||||
|
||||
switch (settings.method) {
|
||||
case 'GET':
|
||||
return this.http
|
||||
.get<T>(settings.url, {headers: this.getHeaders(settings.headers)})
|
||||
.toPromise();
|
||||
case 'POST':
|
||||
return this.http
|
||||
.post<T>(settings.url, settings.data, {
|
||||
headers: this.getHeaders(settings.headers),
|
||||
})
|
||||
.toPromise();
|
||||
case 'PUT':
|
||||
return this.http
|
||||
.put<T>(settings.url, settings.data, {
|
||||
headers: this.getHeaders(settings.headers),
|
||||
})
|
||||
.toPromise();
|
||||
case 'DELETE':
|
||||
return this.http
|
||||
.delete<T>(settings.url, {headers: this.getHeaders(settings.headers)})
|
||||
.toPromise();
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private getHeaders(headers: any): HttpHeaders {
|
||||
let httpHeaders: HttpHeaders = new HttpHeaders();
|
||||
|
||||
if (headers !== undefined) {
|
||||
for (const key of Object.keys(headers)) {
|
||||
httpHeaders = httpHeaders.append(key, headers[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return httpHeaders;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="centeredMessageContainer">
|
||||
<p>{{ 'auth.messages.paia.authorizing' | translate }}</p>
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
import {Component, OnInit, OnDestroy} from '@angular/core';
|
||||
import {NavController} from '@ionic/angular';
|
||||
import {Router} from '@angular/router';
|
||||
import {IAuthAction} from 'ionic-appauth';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {PAIAAuthService} from '../../paia-auth.service';
|
||||
|
||||
@Component({
|
||||
selector: 'auth-callback',
|
||||
templateUrl: './auth-callback-page.component.html',
|
||||
styleUrls: ['./auth-callback-page.component.scss'],
|
||||
})
|
||||
export class PAIAAuthCallbackPageComponent implements OnInit, OnDestroy {
|
||||
sub: Subscription;
|
||||
|
||||
constructor(
|
||||
private auth: PAIAAuthService,
|
||||
private navCtrl: NavController,
|
||||
private router: Router,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.sub = this.auth.events$.subscribe(action => this.postCallback(action));
|
||||
this.auth.authorizationCallback(window.location.origin + this.router.url);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.sub.unsubscribe();
|
||||
}
|
||||
|
||||
async postCallback(_action: IAuthAction) {
|
||||
this.navCtrl.navigateRoot('profile');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
StorageBackend,
|
||||
BasicQueryStringUtils,
|
||||
DefaultCrypto,
|
||||
AuthorizationServiceConfiguration,
|
||||
AuthorizationRequest,
|
||||
StringMap,
|
||||
AuthorizationError,
|
||||
AuthorizationErrorJson,
|
||||
} from '@openid/appauth';
|
||||
import {Browser} from 'ionic-appauth';
|
||||
import {PAIAAuthorizationNotifier} from './paia-authorization-notifier';
|
||||
import {PAIAAuthorizationRequestResponse} from './authorization-request-response';
|
||||
import {
|
||||
PAIAAuthorizationResponse,
|
||||
PAIAAuthorizationResponseJson,
|
||||
} from './paia-authorization-response';
|
||||
|
||||
/** key for authorization request. */
|
||||
const authorizationRequestKey = (handle: string) => {
|
||||
return `${handle}_appauth_authorization_request`;
|
||||
};
|
||||
|
||||
/** key in local storage which represents the current authorization request. */
|
||||
const AUTHORIZATION_REQUEST_HANDLE_KEY =
|
||||
'appauth_current_authorization_request';
|
||||
export const AUTHORIZATION_RESPONSE_KEY = 'auth_response';
|
||||
|
||||
// TODO: PAIA specific ...!!! use whatever you can from the parent class !
|
||||
|
||||
export class PAIAAuthorizationRequestHandler {
|
||||
notifier: PAIAAuthorizationNotifier;
|
||||
|
||||
constructor(
|
||||
private browser: Browser,
|
||||
private storage: StorageBackend,
|
||||
public utils = new BasicQueryStringUtils(),
|
||||
protected crypto = new Crypto(),
|
||||
private generateRandom = new DefaultCrypto(),
|
||||
) {}
|
||||
|
||||
public async performAuthorizationRequest(
|
||||
configuration: AuthorizationServiceConfiguration,
|
||||
request: AuthorizationRequest,
|
||||
): Promise<void> {
|
||||
const handle = this.generateRandom.generateRandom(10);
|
||||
await this.storage.setItem(AUTHORIZATION_REQUEST_HANDLE_KEY, handle);
|
||||
await this.storage.setItem(
|
||||
authorizationRequestKey(handle),
|
||||
JSON.stringify(await request.toJson()),
|
||||
);
|
||||
const url = this.buildRequestUrl(configuration, request);
|
||||
const returnedUrl: string | undefined = await this.browser.showWindow(
|
||||
url,
|
||||
request.redirectUri,
|
||||
);
|
||||
|
||||
// callback may come from showWindow or via another method
|
||||
if (typeof returnedUrl !== 'undefined') {
|
||||
await this.storage.setItem(AUTHORIZATION_RESPONSE_KEY, returnedUrl);
|
||||
await this.completeAuthorizationRequestIfPossible();
|
||||
}
|
||||
}
|
||||
|
||||
protected async completeAuthorizationRequest(): Promise<PAIAAuthorizationRequestResponse> {
|
||||
const handle = await this.storage.getItem(AUTHORIZATION_REQUEST_HANDLE_KEY);
|
||||
|
||||
if (!handle) {
|
||||
throw new Error('Handle Not Available');
|
||||
}
|
||||
|
||||
const request: AuthorizationRequest = this.getAuthorizationRequest(
|
||||
await this.storage.getItem(authorizationRequestKey(handle)),
|
||||
);
|
||||
const queryParameters = this.getQueryParams(
|
||||
await this.storage.getItem(AUTHORIZATION_RESPONSE_KEY),
|
||||
);
|
||||
void this.removeItemsFromStorage(handle);
|
||||
|
||||
// const state: string | undefined = queryParams['state'];
|
||||
const error: string | undefined = queryParameters['error'];
|
||||
|
||||
// TODO: we need state from PAIA (we don't get state at the moment)
|
||||
// if (state !== request.state) {
|
||||
// throw new Error("State Does Not Match");
|
||||
// }
|
||||
|
||||
return <PAIAAuthorizationRequestResponse>{
|
||||
request: request, // request
|
||||
response: !error
|
||||
? this.getAuthorizationResponse(queryParameters)
|
||||
: undefined,
|
||||
error: error ? this.getAuthorizationError(queryParameters) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private getAuthorizationRequest(
|
||||
authRequest: string | null,
|
||||
): AuthorizationRequest {
|
||||
if (authRequest == undefined) {
|
||||
throw new Error('No Auth Request Available');
|
||||
}
|
||||
|
||||
return new AuthorizationRequest(JSON.parse(authRequest));
|
||||
}
|
||||
|
||||
private getAuthorizationError(
|
||||
queryParameters: StringMap,
|
||||
): AuthorizationError {
|
||||
const authorizationErrorJSON: AuthorizationErrorJson = {
|
||||
error: queryParameters['error'],
|
||||
error_description: queryParameters['error_description'],
|
||||
error_uri: undefined,
|
||||
state: queryParameters['state'],
|
||||
};
|
||||
return new AuthorizationError(authorizationErrorJSON);
|
||||
}
|
||||
|
||||
private getAuthorizationResponse(
|
||||
queryParameters: StringMap,
|
||||
): PAIAAuthorizationResponse {
|
||||
const authorizationResponseJSON: PAIAAuthorizationResponseJson = {
|
||||
code: queryParameters['code'],
|
||||
patron: queryParameters['patron'],
|
||||
// TODO: currently PAIA is not providing state
|
||||
state: queryParameters['state'] ?? '',
|
||||
};
|
||||
return new PAIAAuthorizationResponse(authorizationResponseJSON);
|
||||
}
|
||||
|
||||
private async removeItemsFromStorage(handle: string): Promise<void> {
|
||||
await this.storage.removeItem(AUTHORIZATION_REQUEST_HANDLE_KEY);
|
||||
await this.storage.removeItem(authorizationRequestKey(handle));
|
||||
await this.storage.removeItem(AUTHORIZATION_RESPONSE_KEY);
|
||||
}
|
||||
|
||||
private getQueryParams(authResponse: string | null): StringMap {
|
||||
if (authResponse != undefined) {
|
||||
const querySide: string = authResponse.split('#')[0];
|
||||
const parts: string[] = querySide.split('?');
|
||||
if (parts.length !== 2) throw new Error('Invalid auth response string');
|
||||
const hash = parts[1];
|
||||
return this.utils.parseQueryString(hash);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
setAuthorizationNotifier(
|
||||
notifier: PAIAAuthorizationNotifier,
|
||||
): PAIAAuthorizationRequestHandler {
|
||||
this.notifier = notifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
completeAuthorizationRequestIfPossible(): Promise<void> {
|
||||
// call complete authorization if possible to see there might
|
||||
// be a response that needs to be delivered.
|
||||
console.log(
|
||||
`Checking to see if there is an authorization response to be delivered.`,
|
||||
);
|
||||
if (!this.notifier) {
|
||||
console.log(`Notifier is not present on AuthorizationRequest handler.
|
||||
No delivery of result will be possible`);
|
||||
}
|
||||
return this.completeAuthorizationRequest().then(result => {
|
||||
if (!result) {
|
||||
console.log(`No result is available yet.`);
|
||||
}
|
||||
if (result && this.notifier) {
|
||||
this.notifier.onAuthorizationComplete(
|
||||
result.request,
|
||||
result.response,
|
||||
result.error,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to be able to build the authorization request URL.
|
||||
*/
|
||||
protected buildRequestUrl(
|
||||
configuration: AuthorizationServiceConfiguration,
|
||||
request: AuthorizationRequest,
|
||||
) {
|
||||
// build the query string
|
||||
// coerce to any type for convenience
|
||||
const requestMap: StringMap = {
|
||||
redirect_uri: request.redirectUri,
|
||||
client_id: request.clientId,
|
||||
response_type: request.responseType,
|
||||
state: request.state,
|
||||
scope: request.scope,
|
||||
};
|
||||
|
||||
const query = this.utils.stringify(requestMap);
|
||||
const baseUrl = configuration.authorizationEndpoint;
|
||||
|
||||
return `${baseUrl}?${query}&grant_type=client_credentials`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {AuthorizationError, AuthorizationRequest} from '@openid/appauth';
|
||||
import {PAIAAuthorizationResponse} from './paia-authorization-response';
|
||||
|
||||
/**
|
||||
* Represents a structural type holding both authorization request and response.
|
||||
*/
|
||||
export interface PAIAAuthorizationRequestResponse {
|
||||
request: AuthorizationRequest;
|
||||
response: PAIAAuthorizationResponse | null;
|
||||
error: AuthorizationError | null;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {PAIATokenResponse} from './paia-token-response';
|
||||
import {AuthActionBuilder, IAuthAction} from 'ionic-appauth';
|
||||
|
||||
export interface IPAIAAuthAction extends IAuthAction {
|
||||
tokenResponse?: PAIATokenResponse;
|
||||
}
|
||||
|
||||
export class PAIAAuthActionBuilder extends AuthActionBuilder {
|
||||
public static Init(): IPAIAAuthAction {
|
||||
return AuthActionBuilder.Init() as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static SignOutSuccess(): IPAIAAuthAction {
|
||||
return AuthActionBuilder.SignOutSuccess() as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static SignOutFailed(error: Error): IPAIAAuthAction {
|
||||
return AuthActionBuilder.SignOutFailed(error) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static RefreshSuccess(
|
||||
tokenResponse: PAIATokenResponse,
|
||||
): IPAIAAuthAction {
|
||||
return AuthActionBuilder.RefreshSuccess(tokenResponse) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static RefreshFailed(error: Error): IPAIAAuthAction {
|
||||
return AuthActionBuilder.RefreshFailed(error) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static SignInSuccess(
|
||||
tokenResponse: PAIATokenResponse,
|
||||
): IPAIAAuthAction {
|
||||
return AuthActionBuilder.SignInSuccess(tokenResponse) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static SignInFailed(error: Error): IPAIAAuthAction {
|
||||
return AuthActionBuilder.SignInFailed(error) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static LoadTokenFromStorageSuccess(
|
||||
tokenResponse: PAIATokenResponse,
|
||||
): IPAIAAuthAction {
|
||||
return AuthActionBuilder.LoadTokenFromStorageSuccess(
|
||||
tokenResponse,
|
||||
) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static LoadTokenFromStorageFailed(error: Error): IPAIAAuthAction {
|
||||
return AuthActionBuilder.LoadTokenFromStorageFailed(
|
||||
error,
|
||||
) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static RevokeTokensSuccess(): IPAIAAuthAction {
|
||||
return AuthActionBuilder.RevokeTokensSuccess() as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static RevokeTokensFailed(error: Error): IPAIAAuthAction {
|
||||
return AuthActionBuilder.RevokeTokensFailed(error) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static LoadUserInfoSuccess(user: Error): IPAIAAuthAction {
|
||||
return AuthActionBuilder.LoadUserInfoSuccess(user) as IPAIAAuthAction;
|
||||
}
|
||||
|
||||
public static LoadUserInfoFailed(error: Error): IPAIAAuthAction {
|
||||
return AuthActionBuilder.LoadUserInfoFailed(error) as IPAIAAuthAction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
import {
|
||||
AuthorizationError,
|
||||
AuthorizationRequest,
|
||||
AuthorizationRequestJson,
|
||||
AuthorizationServiceConfiguration,
|
||||
BasicQueryStringUtils,
|
||||
DefaultCrypto,
|
||||
JQueryRequestor,
|
||||
LocalStorageBackend,
|
||||
Requestor,
|
||||
StorageBackend,
|
||||
StringMap,
|
||||
} from '@openid/appauth';
|
||||
import {
|
||||
AuthActions,
|
||||
AUTHORIZATION_RESPONSE_KEY,
|
||||
AuthSubject,
|
||||
Browser,
|
||||
DefaultBrowser,
|
||||
EndSessionHandler,
|
||||
IAuthConfig,
|
||||
IonicEndSessionHandler,
|
||||
IonicUserInfoHandler,
|
||||
UserInfoHandler,
|
||||
} from 'ionic-appauth';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {PAIATokenRequestHandler} from './token-request-handler';
|
||||
import {PAIAAuthorizationRequestHandler} from './authorization-request-handler';
|
||||
import {PAIATokenRequest, PAIATokenRequestJson} from './paia-token-request';
|
||||
import {PAIAAuthorizationResponse} from './paia-authorization-response';
|
||||
import {PAIAAuthorizationNotifier} from './paia-authorization-notifier';
|
||||
import {PAIATokenResponse} from './paia-token-response';
|
||||
import {IPAIAAuthAction, PAIAAuthActionBuilder} from './paia-auth-action';
|
||||
|
||||
const TOKEN_KEY = 'auth_paia_token';
|
||||
const AUTH_EXPIRY_BUFFER = 10 * 60 * -1; // 10 mins in seconds
|
||||
|
||||
export interface IAuthService {
|
||||
signIn(authExtras?: StringMap, state?: string): void;
|
||||
signOut(state?: string, revokeTokens?: boolean): void;
|
||||
loadUserInfo(): void;
|
||||
authorizationCallback(callbackUrl: string): void;
|
||||
loadTokenFromStorage(): void;
|
||||
getValidToken(buffer?: number): Promise<PAIATokenResponse>;
|
||||
}
|
||||
|
||||
export class PAIAAuthService implements IAuthService {
|
||||
private _authConfig?: IAuthConfig;
|
||||
|
||||
private _authSubject: AuthSubject = new AuthSubject();
|
||||
|
||||
private _authSubjectV2 = new BehaviorSubject<IPAIAAuthAction>(
|
||||
PAIAAuthActionBuilder.Init(),
|
||||
);
|
||||
|
||||
private _tokenSubject = new BehaviorSubject<PAIATokenResponse | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
private _userSubject = new BehaviorSubject<any>(undefined);
|
||||
|
||||
private _authenticatedSubject = new BehaviorSubject<boolean>(false);
|
||||
|
||||
private _initComplete = new BehaviorSubject<boolean>(false);
|
||||
|
||||
protected tokenHandler: PAIATokenRequestHandler;
|
||||
|
||||
protected userInfoHandler: UserInfoHandler;
|
||||
|
||||
protected requestHandler: PAIAAuthorizationRequestHandler;
|
||||
|
||||
protected endSessionHandler: EndSessionHandler;
|
||||
|
||||
public localConfiguration: AuthorizationServiceConfiguration;
|
||||
|
||||
constructor(
|
||||
protected browser: Browser = new DefaultBrowser(),
|
||||
protected storage: StorageBackend = new LocalStorageBackend(),
|
||||
protected requestor: Requestor = new JQueryRequestor(),
|
||||
utils = new BasicQueryStringUtils(),
|
||||
) {
|
||||
this.tokenHandler = new PAIATokenRequestHandler(requestor);
|
||||
this.userInfoHandler = new IonicUserInfoHandler(requestor);
|
||||
this.requestHandler = new PAIAAuthorizationRequestHandler(
|
||||
browser,
|
||||
storage,
|
||||
utils,
|
||||
crypto,
|
||||
);
|
||||
this.endSessionHandler = new IonicEndSessionHandler(browser);
|
||||
}
|
||||
|
||||
get token$(): Observable<PAIATokenResponse | undefined> {
|
||||
return this._tokenSubject.asObservable();
|
||||
}
|
||||
|
||||
get isAuthenticated$(): Observable<boolean> {
|
||||
return this._authenticatedSubject.asObservable();
|
||||
}
|
||||
|
||||
get initComplete$(): Observable<boolean> {
|
||||
return this._initComplete.asObservable();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
get user$(): Observable<any> {
|
||||
return this._userSubject.asObservable();
|
||||
}
|
||||
|
||||
get events$(): Observable<IPAIAAuthAction> {
|
||||
return this._authSubjectV2.asObservable();
|
||||
}
|
||||
|
||||
get authConfig(): IAuthConfig {
|
||||
if (!this._authConfig) throw new Error('AuthConfig Not Defined');
|
||||
|
||||
return this._authConfig;
|
||||
}
|
||||
|
||||
set authConfig(value: IAuthConfig) {
|
||||
this._authConfig = value;
|
||||
}
|
||||
|
||||
get configuration(): Promise<AuthorizationServiceConfiguration> {
|
||||
if (!this.localConfiguration)
|
||||
throw new Error('Local Configuration Not Defined');
|
||||
|
||||
return Promise.resolve(this.localConfiguration);
|
||||
}
|
||||
|
||||
public async init() {
|
||||
this.setupAuthorizationNotifier();
|
||||
this.loadTokenFromStorage();
|
||||
}
|
||||
|
||||
protected notifyActionListers(action: IPAIAAuthAction) {
|
||||
this._authSubjectV2.next(action);
|
||||
this._authSubject.notify(action);
|
||||
|
||||
/* eslint-disable unicorn/no-useless-undefined */
|
||||
switch (action.action) {
|
||||
case AuthActions.SignInFailed:
|
||||
case AuthActions.SignOutSuccess:
|
||||
case AuthActions.SignOutFailed:
|
||||
this._tokenSubject.next(undefined);
|
||||
this._userSubject.next(undefined);
|
||||
this._authenticatedSubject.next(false);
|
||||
break;
|
||||
case AuthActions.LoadTokenFromStorageFailed:
|
||||
this._tokenSubject.next(undefined);
|
||||
this._userSubject.next(undefined);
|
||||
this._authenticatedSubject.next(false);
|
||||
this._initComplete.next(true);
|
||||
break;
|
||||
case AuthActions.SignInSuccess:
|
||||
this._tokenSubject.next(action.tokenResponse);
|
||||
this._authenticatedSubject.next(true);
|
||||
break;
|
||||
case AuthActions.LoadTokenFromStorageSuccess:
|
||||
this._tokenSubject.next(action.tokenResponse);
|
||||
this._authenticatedSubject.next(true);
|
||||
this._initComplete.next(true);
|
||||
break;
|
||||
case AuthActions.RevokeTokensSuccess:
|
||||
this._tokenSubject.next(undefined);
|
||||
break;
|
||||
case AuthActions.LoadUserInfoSuccess:
|
||||
this._userSubject.next(action.user);
|
||||
break;
|
||||
case AuthActions.LoadUserInfoFailed:
|
||||
this._userSubject.next(undefined);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected setupAuthorizationNotifier() {
|
||||
const notifier = new PAIAAuthorizationNotifier();
|
||||
this.requestHandler.setAuthorizationNotifier(notifier);
|
||||
notifier.setAuthorizationListener((request, response, error) =>
|
||||
this.onAuthorizationNotification(request, response, error),
|
||||
);
|
||||
}
|
||||
|
||||
protected onAuthorizationNotification(
|
||||
request: AuthorizationRequest,
|
||||
response: PAIAAuthorizationResponse | null,
|
||||
error: AuthorizationError | null,
|
||||
) {
|
||||
const codeVerifier: string | undefined =
|
||||
request.internal != undefined && this.authConfig.pkce
|
||||
? request.internal.code_verifier
|
||||
: undefined;
|
||||
|
||||
if (response != undefined) {
|
||||
this.requestAccessToken(response.code, response.patron, codeVerifier);
|
||||
} else if (error != undefined) {
|
||||
throw new Error(error.errorDescription);
|
||||
} else {
|
||||
throw new Error('Unknown Error With Authentication');
|
||||
}
|
||||
}
|
||||
|
||||
protected async internalAuthorizationCallback(url: string) {
|
||||
this.browser.closeWindow();
|
||||
await this.storage.setItem(AUTHORIZATION_RESPONSE_KEY, url);
|
||||
return this.requestHandler.completeAuthorizationRequestIfPossible();
|
||||
}
|
||||
|
||||
protected async performAuthorizationRequest(
|
||||
authExtras?: StringMap,
|
||||
state?: string,
|
||||
): Promise<void> {
|
||||
const requestJson: AuthorizationRequestJson = {
|
||||
response_type: AuthorizationRequest.RESPONSE_TYPE_CODE,
|
||||
client_id: this.authConfig.client_id,
|
||||
redirect_uri: this.authConfig.redirect_url,
|
||||
scope: this.authConfig.scopes,
|
||||
extras: authExtras,
|
||||
state: state || undefined,
|
||||
};
|
||||
|
||||
const request = new AuthorizationRequest(
|
||||
requestJson,
|
||||
new DefaultCrypto(),
|
||||
this.authConfig.pkce,
|
||||
);
|
||||
|
||||
if (this.authConfig.pkce) await request.setupCodeVerifier();
|
||||
|
||||
return this.requestHandler.performAuthorizationRequest(
|
||||
await this.configuration,
|
||||
request,
|
||||
);
|
||||
}
|
||||
|
||||
protected async requestAccessToken(
|
||||
code: string,
|
||||
patron: string,
|
||||
codeVerifier?: string,
|
||||
): Promise<void> {
|
||||
const requestJSON: PAIATokenRequestJson = {
|
||||
code: code,
|
||||
patron: patron,
|
||||
extras: codeVerifier
|
||||
? {
|
||||
code_verifier: codeVerifier,
|
||||
}
|
||||
: {},
|
||||
};
|
||||
|
||||
const token: PAIATokenResponse =
|
||||
await this.tokenHandler.performTokenRequest(
|
||||
await this.configuration,
|
||||
new PAIATokenRequest(requestJSON),
|
||||
);
|
||||
await this.storage.setItem(TOKEN_KEY, JSON.stringify(token.toJson()));
|
||||
this.notifyActionListers(PAIAAuthActionBuilder.SignInSuccess(token));
|
||||
}
|
||||
|
||||
public async revokeTokens() {
|
||||
// Note: only locally
|
||||
await this.storage.removeItem(TOKEN_KEY);
|
||||
this.notifyActionListers(PAIAAuthActionBuilder.RevokeTokensSuccess());
|
||||
}
|
||||
|
||||
public async signOut() {
|
||||
await this.revokeTokens().catch(error =>
|
||||
this.notifyActionListers(PAIAAuthActionBuilder.SignOutFailed(error)),
|
||||
);
|
||||
this.notifyActionListers(PAIAAuthActionBuilder.SignOutSuccess());
|
||||
}
|
||||
|
||||
protected async internalLoadTokenFromStorage() {
|
||||
let token: PAIATokenResponse | undefined;
|
||||
const tokenResponseString: string | null = await this.storage.getItem(
|
||||
TOKEN_KEY,
|
||||
);
|
||||
|
||||
if (tokenResponseString != undefined) {
|
||||
token = new PAIATokenResponse(JSON.parse(tokenResponseString));
|
||||
|
||||
if (token) {
|
||||
return this.notifyActionListers(
|
||||
PAIAAuthActionBuilder.LoadTokenFromStorageSuccess(token),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('No Token In Storage');
|
||||
}
|
||||
|
||||
protected async internalRequestUserInfo() {
|
||||
if (this._tokenSubject.value) {
|
||||
const userInfo = await this.userInfoHandler.performUserInfoRequest(
|
||||
await this.configuration,
|
||||
this._tokenSubject.value,
|
||||
);
|
||||
this.notifyActionListers(
|
||||
PAIAAuthActionBuilder.LoadUserInfoSuccess(userInfo),
|
||||
);
|
||||
} else {
|
||||
throw new Error('No Token Available');
|
||||
}
|
||||
}
|
||||
|
||||
public async loadTokenFromStorage() {
|
||||
await this.internalLoadTokenFromStorage().catch(error => {
|
||||
this.notifyActionListers(
|
||||
PAIAAuthActionBuilder.LoadTokenFromStorageFailed(error),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public async signIn(authExtras?: StringMap, state?: string) {
|
||||
await this.performAuthorizationRequest(authExtras, state).catch(error => {
|
||||
this.notifyActionListers(PAIAAuthActionBuilder.SignInFailed(error));
|
||||
});
|
||||
}
|
||||
|
||||
public async loadUserInfo() {
|
||||
await this.internalRequestUserInfo().catch(error => {
|
||||
this.notifyActionListers(PAIAAuthActionBuilder.LoadUserInfoFailed(error));
|
||||
});
|
||||
}
|
||||
|
||||
public authorizationCallback(callbackUrl: string): void {
|
||||
this.internalAuthorizationCallback(callbackUrl).catch(error => {
|
||||
this.notifyActionListers(PAIAAuthActionBuilder.SignInFailed(error));
|
||||
});
|
||||
}
|
||||
|
||||
public async getValidToken(
|
||||
buffer: number = AUTH_EXPIRY_BUFFER,
|
||||
): Promise<PAIATokenResponse> {
|
||||
if (this._tokenSubject.value && this._tokenSubject.value.isValid(buffer)) {
|
||||
return this._tokenSubject.value;
|
||||
}
|
||||
|
||||
throw new Error('Unable To Obtain Valid Token');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {AuthorizationError, AuthorizationRequest} from '@openid/appauth';
|
||||
import {PAIAAuthorizationResponse} from './paia-authorization-response';
|
||||
|
||||
export type PAIAAuthorizationListener = (
|
||||
request: AuthorizationRequest,
|
||||
response: PAIAAuthorizationResponse | null,
|
||||
error: AuthorizationError | null,
|
||||
) => void;
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {PAIAAuthorizationListener} from './paia-authorization-listener';
|
||||
import {AuthorizationError, AuthorizationRequest} from '@openid/appauth';
|
||||
import {PAIAAuthorizationResponse} from './paia-authorization-response';
|
||||
|
||||
export class PAIAAuthorizationNotifier {
|
||||
// eslint-disable-next-line unicorn/no-null
|
||||
private listener: PAIAAuthorizationListener | null = null;
|
||||
|
||||
setAuthorizationListener(listener: PAIAAuthorizationListener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* The authorization complete callback.
|
||||
*/
|
||||
onAuthorizationComplete(
|
||||
request: AuthorizationRequest,
|
||||
response: PAIAAuthorizationResponse | null,
|
||||
error: AuthorizationError | null,
|
||||
): void {
|
||||
if (this.listener) {
|
||||
// complete authorization request
|
||||
this.listener(request, response, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface PAIAAuthorizationResponseJson {
|
||||
code: string;
|
||||
state: string;
|
||||
patron: string;
|
||||
}
|
||||
|
||||
export class PAIAAuthorizationResponse {
|
||||
code: string;
|
||||
|
||||
state: string;
|
||||
|
||||
patron: string;
|
||||
|
||||
constructor(response: PAIAAuthorizationResponseJson) {
|
||||
this.code = response.code;
|
||||
this.state = response.state;
|
||||
this.patron = response.patron;
|
||||
}
|
||||
|
||||
toJson(): PAIAAuthorizationResponseJson {
|
||||
return {code: this.code, state: this.state, patron: this.patron};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {StringMap} from '@openid/appauth';
|
||||
|
||||
// TODO: add documentation
|
||||
export interface PAIATokenRequestJson {
|
||||
code: string;
|
||||
patron: string;
|
||||
extras?: StringMap;
|
||||
}
|
||||
|
||||
export class PAIATokenRequest {
|
||||
code: string;
|
||||
|
||||
patron: string;
|
||||
|
||||
extras?: StringMap;
|
||||
|
||||
constructor(request: PAIATokenRequestJson) {
|
||||
this.code = request.code;
|
||||
this.patron = request.patron;
|
||||
this.extras = request.extras;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes a TokenRequest to a JavaScript object.
|
||||
*/
|
||||
toJson(): PAIATokenRequestJson {
|
||||
return {
|
||||
code: this.code,
|
||||
patron: this.patron,
|
||||
extras: this.extras,
|
||||
};
|
||||
}
|
||||
|
||||
toStringMap(): StringMap {
|
||||
const map: StringMap = {
|
||||
patron: this.patron,
|
||||
code: this.code,
|
||||
};
|
||||
|
||||
// copy over extras
|
||||
if (this.extras) {
|
||||
for (const extra in this.extras) {
|
||||
if (this.extras.hasOwnProperty(extra) && !map.hasOwnProperty(extra)) {
|
||||
// check before inserting to requestMap
|
||||
map[extra] = this.extras[extra];
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {TokenResponse, TokenResponseJson} from '@openid/appauth';
|
||||
import {nowInSeconds} from '@openid/appauth';
|
||||
|
||||
const AUTH_EXPIRY_BUFFER = 10 * 60 * -1; // 10 mins in seconds
|
||||
|
||||
export interface PAIATokenResponseJson extends TokenResponseJson {
|
||||
patron: string;
|
||||
}
|
||||
|
||||
export class PAIATokenResponse extends TokenResponse {
|
||||
patron: string;
|
||||
|
||||
constructor(response: PAIATokenResponseJson) {
|
||||
super(response);
|
||||
this.patron = response.patron;
|
||||
}
|
||||
|
||||
toJson(): PAIATokenResponseJson {
|
||||
return {
|
||||
access_token: this.accessToken,
|
||||
id_token: this.idToken,
|
||||
refresh_token: this.refreshToken,
|
||||
scope: this.scope,
|
||||
token_type: this.tokenType,
|
||||
issued_at: this.issuedAt,
|
||||
expires_in: this.expiresIn?.toString(),
|
||||
patron: this.patron,
|
||||
};
|
||||
}
|
||||
|
||||
isValid(buffer: number = AUTH_EXPIRY_BUFFER): boolean {
|
||||
if (this.expiresIn) {
|
||||
const now = nowInSeconds();
|
||||
return now < this.issuedAt + this.expiresIn + buffer;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {AuthorizationServiceConfiguration, Requestor} from '@openid/appauth';
|
||||
import {PAIATokenResponse} from './paia-token-response';
|
||||
|
||||
export interface UserInfoHandler {
|
||||
performUserInfoRequest(
|
||||
configuration: AuthorizationServiceConfiguration,
|
||||
token: PAIATokenResponse,
|
||||
): Promise<unknown>;
|
||||
}
|
||||
|
||||
export class PAIAUserInfoHandler implements UserInfoHandler {
|
||||
constructor(private requestor: Requestor) {}
|
||||
|
||||
public async performUserInfoRequest(
|
||||
configuration: AuthorizationServiceConfiguration,
|
||||
token: PAIATokenResponse,
|
||||
): Promise<unknown> {
|
||||
const settings: JQueryAjaxSettings = {
|
||||
url: `${configuration.userInfoEndpoint}/${token.patron}`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: `${
|
||||
token.tokenType == 'bearer' ? 'Bearer' : token.tokenType
|
||||
} ${token.accessToken}`,
|
||||
},
|
||||
};
|
||||
|
||||
return this.requestor.xhr(settings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2021 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {
|
||||
TokenErrorJson,
|
||||
AuthorizationServiceConfiguration,
|
||||
RevokeTokenRequest,
|
||||
Requestor,
|
||||
JQueryRequestor,
|
||||
BasicQueryStringUtils,
|
||||
QueryStringUtils,
|
||||
AppAuthError,
|
||||
TokenError,
|
||||
} from '@openid/appauth';
|
||||
import {PAIATokenRequest} from './paia-token-request';
|
||||
import {PAIATokenResponse, PAIATokenResponseJson} from './paia-token-response';
|
||||
|
||||
export class PAIATokenRequestHandler {
|
||||
constructor(
|
||||
public readonly requestor: Requestor = new JQueryRequestor(),
|
||||
public readonly utils: QueryStringUtils = new BasicQueryStringUtils(),
|
||||
) {}
|
||||
|
||||
private isTokenResponse(
|
||||
response: PAIATokenResponseJson | TokenErrorJson,
|
||||
): response is PAIATokenResponseJson {
|
||||
return (response as TokenErrorJson).error === undefined;
|
||||
}
|
||||
|
||||
performRevokeTokenRequest(
|
||||
configuration: AuthorizationServiceConfiguration,
|
||||
request: RevokeTokenRequest,
|
||||
): Promise<boolean> {
|
||||
const revokeTokenResponse = this.requestor.xhr<boolean>({
|
||||
url: configuration.revocationEndpoint,
|
||||
method: 'GET',
|
||||
// headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||
data: this.utils.stringify(request.toStringMap()),
|
||||
});
|
||||
|
||||
return revokeTokenResponse.then(_response => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
performTokenRequest(
|
||||
configuration: AuthorizationServiceConfiguration,
|
||||
request: PAIATokenRequest,
|
||||
): Promise<PAIATokenResponse> {
|
||||
const tokenResponse = this.requestor.xhr<
|
||||
PAIATokenResponseJson | TokenErrorJson
|
||||
>({
|
||||
url: configuration.tokenEndpoint,
|
||||
method: 'POST',
|
||||
data: {
|
||||
patron: request.patron,
|
||||
grant_type: 'client_credentials',
|
||||
},
|
||||
headers: {
|
||||
'Authorization': `Basic ${request.code}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
return tokenResponse.then(response => {
|
||||
return this.isTokenResponse(response)
|
||||
? new PAIATokenResponse(response)
|
||||
: Promise.reject<PAIATokenResponse>(
|
||||
new AppAuthError(response.error, new TokenError(response)),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface IUserInfo {
|
||||
display_name: string;
|
||||
role: string;
|
||||
email: string;
|
||||
user_name: string;
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {Component} from '@angular/core';
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
||||
import {
|
||||
SCAppConfigurationMenuCategory,
|
||||
@@ -20,8 +20,7 @@ import {
|
||||
SCThingTranslator,
|
||||
SCTranslations,
|
||||
} from '@openstapps/core';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
import {ConfigProvider} from '../../config/config.provider';
|
||||
import {NavigationService} from './navigation.service';
|
||||
|
||||
/**
|
||||
* Generated class for the MenuPage page.
|
||||
@@ -34,7 +33,7 @@ import {ConfigProvider} from '../../config/config.provider';
|
||||
styleUrls: ['navigation.scss'],
|
||||
templateUrl: 'navigation.html',
|
||||
})
|
||||
export class NavigationComponent {
|
||||
export class NavigationComponent implements OnInit {
|
||||
/**
|
||||
* Possible languages to be used for translation
|
||||
*/
|
||||
@@ -60,11 +59,9 @@ export class NavigationComponent {
|
||||
translator: SCThingTranslator;
|
||||
|
||||
constructor(
|
||||
private readonly configProvider: ConfigProvider,
|
||||
public translateService: TranslateService,
|
||||
private readonly logger: NGXLogger,
|
||||
private navigationService: NavigationService,
|
||||
) {
|
||||
void this.loadMenuEntries();
|
||||
translateService.onLangChange.subscribe((event: LangChangeEvent) => {
|
||||
this.language = event.lang as keyof SCTranslations<SCLanguage>;
|
||||
this.translator = new SCThingTranslator(this.language);
|
||||
@@ -72,20 +69,7 @@ export class NavigationComponent {
|
||||
this.translator = new SCThingTranslator('en');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads menu entries from configProvider
|
||||
*/
|
||||
async loadMenuEntries() {
|
||||
try {
|
||||
this.menu = (await this.configProvider.getValue(
|
||||
'menus',
|
||||
)) as SCAppConfigurationMenuCategory[];
|
||||
} catch (error) {
|
||||
this.logger.error(`error from loading menu entries: ${error}`);
|
||||
async ngOnInit() {
|
||||
this.menu = await this.navigationService.getMenu();
|
||||
}
|
||||
}
|
||||
|
||||
// openPage(page) {
|
||||
// this.nav.setRoot(page.component);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {SCAppConfigurationMenuCategory} from '@openstapps/core';
|
||||
import {ConfigProvider} from '../../config/config.provider';
|
||||
import {NGXLogger} from 'ngx-logger';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class NavigationService {
|
||||
constructor(
|
||||
private configProvider: ConfigProvider,
|
||||
private logger: NGXLogger,
|
||||
) {}
|
||||
|
||||
async getMenu() {
|
||||
let menu: SCAppConfigurationMenuCategory[] = [];
|
||||
try {
|
||||
menu = (await this.configProvider.getValue(
|
||||
'menus',
|
||||
)) as SCAppConfigurationMenuCategory[];
|
||||
} catch (error) {
|
||||
this.logger.error(`error from loading menu entries: ${error}`);
|
||||
}
|
||||
// TODO: Load if from the backend (config)
|
||||
menu[1].items.unshift({
|
||||
icon: 'person',
|
||||
route: '/profile',
|
||||
title: 'profile',
|
||||
translations: {
|
||||
de: {
|
||||
title: 'Profil',
|
||||
},
|
||||
en: {
|
||||
title: 'profile',
|
||||
},
|
||||
},
|
||||
});
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
<ion-menu-button></ion-menu-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ 'profile.title' | translate | titlecase }}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<section>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<ion-card *ngIf="userInfo">
|
||||
<ion-card-content>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col size="3">
|
||||
<ion-thumbnail>
|
||||
<ion-icon name="person"></ion-icon>
|
||||
</ion-thumbnail>
|
||||
</ion-col>
|
||||
<ion-col size="9">
|
||||
<ion-row class="main-info">
|
||||
<span
|
||||
>{{ userInfo.givenName }}
|
||||
{{ userInfo.familyName }}</span
|
||||
>
|
||||
</ion-row>
|
||||
<ion-row class="additional-info">
|
||||
<span>{{ userInfo.email }}</span>
|
||||
<span
|
||||
>{{
|
||||
'profile.userInfo.studentId' | translate | titlecase
|
||||
}}: {{ userInfo.studentId }}</span
|
||||
>
|
||||
</ion-row>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col class="login">
|
||||
<a *ngIf="!data.default.loggedIn; else loggedIn" (click)="signIn()">{{
|
||||
'profile.buttons.default.log_in' | translate | titlecase
|
||||
}}</a>
|
||||
<ng-template #loggedIn
|
||||
><a (click)="signOut()">{{
|
||||
'profile.buttons.default.log_out' | translate | titlecase
|
||||
}}</a></ng-template
|
||||
>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
<ion-row>
|
||||
<ion-col class="login">
|
||||
<a
|
||||
*ngIf="!data.paia.loggedIn; else paiaLoggedIn"
|
||||
(click)="signInPAIA()"
|
||||
>{{ 'profile.buttons.paia.log_in' | translate | titlecase }}</a
|
||||
>
|
||||
<ng-template #paiaLoggedIn
|
||||
><a (click)="signOutPAIA()">{{
|
||||
'profile.buttons.paia.log_out' | translate | titlecase
|
||||
}}</a></ng-template
|
||||
>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</section>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,25 @@
|
||||
:host {
|
||||
ion-col.login {
|
||||
text-align: center;
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
ion-thumbnail {
|
||||
background: var(--placeholder-gray);
|
||||
--size: 64px;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
ion-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: white;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
ion-row.main-info {
|
||||
font-weight: bold;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {AuthModule} from '../../auth/auth.module';
|
||||
import {ProfilePageComponent} from './profile-page.component';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
|
||||
describe('ProfilePage', () => {
|
||||
let component: ProfilePageComponent;
|
||||
let fixture: ComponentFixture<ProfilePageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProfilePageComponent],
|
||||
imports: [
|
||||
HttpClientTestingModule,
|
||||
RouterTestingModule,
|
||||
AuthModule,
|
||||
TranslateModule.forRoot(),
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProfilePageComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {IonicUserInfoHandler} from 'ionic-appauth';
|
||||
import {DefaultAuthService} from '../../auth/default-auth.service';
|
||||
import {Requestor, TokenResponse} from '@openid/appauth';
|
||||
import {PAIAAuthService} from '../../auth/paia/paia-auth.service';
|
||||
import {SCAuthorizationProviderType, SCUserConfiguration} from '../user';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {AuthHelperService} from '../../auth/auth-helper.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './profile-page.component.html',
|
||||
styleUrls: ['./profile-page.component.scss'],
|
||||
})
|
||||
export class ProfilePageComponent implements OnInit, OnDestroy {
|
||||
data: {[key in SCAuthorizationProviderType]: {loggedIn: boolean}} = {
|
||||
default: {loggedIn: false},
|
||||
paia: {loggedIn: false},
|
||||
};
|
||||
|
||||
userInfo?: SCUserConfiguration;
|
||||
|
||||
subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(
|
||||
private defaultAuth: DefaultAuthService,
|
||||
private paiaAuth: PAIAAuthService,
|
||||
private requestor: Requestor,
|
||||
private authHelperService: AuthHelperService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.subscriptions.push(
|
||||
this.defaultAuth.token$.subscribe(_token => {
|
||||
this.defaultAuth
|
||||
.getValidToken()
|
||||
.then(token => {
|
||||
this.data.default.loggedIn = true;
|
||||
this.getUserInfo(token);
|
||||
})
|
||||
.catch(_error => {
|
||||
this.data.default.loggedIn = false;
|
||||
});
|
||||
}),
|
||||
this.paiaAuth.token$.subscribe(_token => {
|
||||
this.paiaAuth
|
||||
.getValidToken()
|
||||
.then(_token => {
|
||||
this.data.paia.loggedIn = true;
|
||||
})
|
||||
.catch(_error => {
|
||||
this.data.paia.loggedIn = false;
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
getUserInfo(token: TokenResponse) {
|
||||
const userInfoHandler = new IonicUserInfoHandler(this.requestor);
|
||||
|
||||
userInfoHandler
|
||||
.performUserInfoRequest(this.defaultAuth.localConfiguration, token)
|
||||
.then(userInfo => {
|
||||
this.userInfo = this.authHelperService.getUserFromUserInfo(userInfo);
|
||||
});
|
||||
}
|
||||
|
||||
public signIn() {
|
||||
this.defaultAuth.signIn();
|
||||
}
|
||||
|
||||
signInPAIA() {
|
||||
this.paiaAuth.signIn();
|
||||
}
|
||||
|
||||
async signOut() {
|
||||
await this.defaultAuth.signOut();
|
||||
this.userInfo = undefined;
|
||||
}
|
||||
|
||||
async signOutPAIA() {
|
||||
await this.paiaAuth.signOut();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
for (const subscription of this.subscriptions) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {Routes, RouterModule} from '@angular/router';
|
||||
import {IonicModule} from '@ionic/angular';
|
||||
import {ProfilePageComponent} from './page/profile-page.component';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: 'profile',
|
||||
component: ProfilePageComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [ProfilePageComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
IonicModule,
|
||||
RouterModule.forChild(routes),
|
||||
TranslateModule,
|
||||
],
|
||||
})
|
||||
export class ProfilePageModule {}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (C) 2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO: Take it from the StApps Core
|
||||
*/
|
||||
import {SCAcademicPriceGroup} from '@openstapps/core';
|
||||
|
||||
/**
|
||||
* A user configuration
|
||||
*/
|
||||
export interface SCUserConfiguration {
|
||||
/**
|
||||
* User's e-mail
|
||||
*/
|
||||
email?: string;
|
||||
|
||||
/**
|
||||
* User's family name
|
||||
*/
|
||||
familyName?: string;
|
||||
|
||||
/**
|
||||
* User's given name
|
||||
*/
|
||||
givenName?: string;
|
||||
|
||||
/**
|
||||
* ID given to the user
|
||||
*/
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* The complete name of the user combining all the parts of the name into one
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* Role assigned to the user
|
||||
*/
|
||||
role: keyof SCAcademicPriceGroup;
|
||||
|
||||
/**
|
||||
* Student ID given to the user
|
||||
*/
|
||||
studentId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Take it from the backend's config
|
||||
*/
|
||||
type mapping = {[key in keyof SCUserConfiguration]: string};
|
||||
|
||||
/**
|
||||
* TODO: Take it from the backend's config
|
||||
*/
|
||||
export const userMapping: mapping = {
|
||||
id: 'id',
|
||||
name: 'sn',
|
||||
role: 'attributes.eduPersonPrimaryAffiliation',
|
||||
email: 'attributes.mailPrimaryAddress',
|
||||
studentId: 'attributes.employeeNumber',
|
||||
givenName: 'attributes.givenName',
|
||||
familyName: 'attributes.sn',
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Take it from the StApps Core
|
||||
*/
|
||||
export type SCAuthorizationProviderType = 'default' | 'paia';
|
||||
@@ -13,6 +13,20 @@
|
||||
"UNKNOWN": "Unbekannter Fehler."
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"messages": {
|
||||
"default": {
|
||||
"authorizing": "Autorisierung läuft...",
|
||||
"logged_in_success": "Erfolgreich eingeloggt.",
|
||||
"logged_out_success": "Erfolgreich ausgeloggt."
|
||||
},
|
||||
"paia": {
|
||||
"authorizing": "Autorisierung (Bibliothek) läuft...",
|
||||
"logged_in_success": "Erfolgreich ins Bibliothekskonto eingeloggt.",
|
||||
"logged_out_success": "Erfolgreich aus dem Bibliothekskonto ausgeloggt."
|
||||
}
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"openingHours": {
|
||||
"closed_until": "Geschlossen bis",
|
||||
@@ -202,6 +216,21 @@
|
||||
"pastEvent": "Event ist vorbei"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"buttons": {
|
||||
"default": {
|
||||
"log_in": "Login",
|
||||
"log_out": "Ausloggen"
|
||||
},
|
||||
"paia": {
|
||||
"log_in": "Login Bibliothek",
|
||||
"log_out": "Ausloggen (Bibliothek)"
|
||||
}
|
||||
},
|
||||
"userInfo": {
|
||||
"studentId": "Matrikelnr."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"resetAlert.title": "Alle Einstellungen zurücksetzen?",
|
||||
"resetAlert.message": "Sind Sie sich sicher, alle Einstellungen auf ihre Anfangswerte zurückzusetzen?",
|
||||
|
||||
@@ -13,6 +13,20 @@
|
||||
"UNKNOWN": "Unknown problem."
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"messages": {
|
||||
"default": {
|
||||
"authorizing": "Authorizing...",
|
||||
"logged_in_success": "Successfully logged in.",
|
||||
"logged_out_success": "Successfully logged out."
|
||||
},
|
||||
"paia": {
|
||||
"authorizing": "Authorizing (library)...",
|
||||
"logged_in_success": "Successfully logged in to library.",
|
||||
"logged_out_success": "Successfully logged out from library."
|
||||
}
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"openingHours": {
|
||||
"closed_until": "Closed until",
|
||||
@@ -202,6 +216,22 @@
|
||||
"pastEvent": "Event is over"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"title": "Profile",
|
||||
"buttons": {
|
||||
"default": {
|
||||
"log_in": "Log In",
|
||||
"log_out": "Log Out"
|
||||
},
|
||||
"paia": {
|
||||
"log_in": "Library Login",
|
||||
"log_out": "Log Out (Library)"
|
||||
}
|
||||
},
|
||||
"userInfo": {
|
||||
"studentId": "Matriculation Nr."
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
"resetAlert.title": "Reset all settings?",
|
||||
"resetAlert.message": "Are you sure to reset all settings to their default values?",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 StApps
|
||||
* Copyright (C) 2018-2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
@@ -12,9 +12,74 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
import {AuthorizationServiceConfigurationJson} from '@openid/appauth';
|
||||
import {IAuthConfig} from 'ionic-appauth';
|
||||
// import config from 'capacitor.config';
|
||||
|
||||
const appDomain = 'mobile.app.uni-frankfurt.de';
|
||||
|
||||
export const environment = {
|
||||
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
||||
appDomain: 'mobile.app.uni-frankfurt.de',
|
||||
backend_version: '2.0.0',
|
||||
use_fake_backend: true,
|
||||
production: false,
|
||||
oauth2: {
|
||||
client: {
|
||||
his: {
|
||||
client_id: '1cac3f99-33fa-4234-8438-979f07e0cdab',
|
||||
client_secret: 'CLIENT_SECRET',
|
||||
server_host: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0',
|
||||
redirect_url: `https://${appDomain}/auth/callback`,
|
||||
scopes: '',
|
||||
pkce: true,
|
||||
} as IAuthConfig,
|
||||
paia: {
|
||||
client_id: '',
|
||||
client_secret: '',
|
||||
server_host:
|
||||
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
// TODO: Use Custom URL Scheme (ideally bundle ID from capacitor.config)
|
||||
redirect_url: `https://${appDomain}/auth/paia/callback`,
|
||||
scopes: '',
|
||||
pkce: true,
|
||||
} as IAuthConfig,
|
||||
},
|
||||
service: {
|
||||
his: {
|
||||
authorization_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/authorize',
|
||||
token_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/accessToken',
|
||||
userinfo_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/profile',
|
||||
} as AuthorizationServiceConfigurationJson,
|
||||
paia: {
|
||||
authorization_endpoint:
|
||||
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
token_endpoint: 'https://hds.hebis.de:8443/auth/login',
|
||||
userinfo_endpoint: 'https://hds.hebis.de:8443/core',
|
||||
} as AuthorizationServiceConfigurationJson,
|
||||
},
|
||||
endpointMappings: {
|
||||
userinfo: {
|
||||
id: 'employeeNumber',
|
||||
given_name: 'givenName',
|
||||
family_name: 'sn',
|
||||
email: 'mailPrimaryAddress',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* In development mode, to ignore zone related error stack frames such as
|
||||
* `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
|
||||
* import the following file, but please comment it out in production mode
|
||||
* because it will have performance impact when throw error
|
||||
*/
|
||||
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 StApps
|
||||
* Copyright (C) 2018-2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
@@ -12,10 +12,74 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// eslint-disable-next-line unicorn/prevent-abbreviations
|
||||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
import {AuthorizationServiceConfigurationJson} from '@openid/appauth';
|
||||
import {IAuthConfig} from 'ionic-appauth';
|
||||
// import config from 'capacitor.config';
|
||||
|
||||
const appDomain = 'mobile.app.uni-frankfurt.de';
|
||||
|
||||
export const environment = {
|
||||
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
||||
appDomain: 'mobile.app.uni-frankfurt.de',
|
||||
backend_version: '2.0.0',
|
||||
use_fake_backend: false,
|
||||
production: true,
|
||||
production: false,
|
||||
oauth2: {
|
||||
client: {
|
||||
his: {
|
||||
client_id: '1cac3f99-33fa-4234-8438-979f07e0cdab',
|
||||
client_secret: 'CLIENT_SECRET',
|
||||
server_host: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0',
|
||||
redirect_url: `https://${appDomain}/auth/callback`,
|
||||
scopes: '',
|
||||
pkce: true,
|
||||
} as IAuthConfig,
|
||||
paia: {
|
||||
client_id: '',
|
||||
client_secret: '',
|
||||
server_host:
|
||||
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
// TODO: Use Custom URL Scheme (ideally bundle ID from capacitor.config)
|
||||
redirect_url: `https://${appDomain}/auth/paia/callback`,
|
||||
scopes: '',
|
||||
pkce: true,
|
||||
} as IAuthConfig,
|
||||
},
|
||||
service: {
|
||||
his: {
|
||||
authorization_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/authorize',
|
||||
token_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/accessToken',
|
||||
userinfo_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/profile',
|
||||
} as AuthorizationServiceConfigurationJson,
|
||||
paia: {
|
||||
authorization_endpoint:
|
||||
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
token_endpoint: 'https://hds.hebis.de:8443/auth/login',
|
||||
userinfo_endpoint: 'https://hds.hebis.de:8443/core',
|
||||
} as AuthorizationServiceConfigurationJson,
|
||||
},
|
||||
endpointMappings: {
|
||||
userinfo: {
|
||||
id: 'employeeNumber',
|
||||
given_name: 'givenName',
|
||||
family_name: 'sn',
|
||||
email: 'mailPrimaryAddress',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* In development mode, to ignore zone related error stack frames such as
|
||||
* `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
|
||||
* import the following file, but please comment it out in production mode
|
||||
* because it will have performance impact when throw error
|
||||
*/
|
||||
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2020 StApps
|
||||
* Copyright (C) 2018-2022 StApps
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 3.
|
||||
@@ -16,11 +16,65 @@
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
import {AuthorizationServiceConfigurationJson} from '@openid/appauth';
|
||||
import {IAuthConfig} from 'ionic-appauth';
|
||||
// import config from 'capacitor.config';
|
||||
|
||||
const appDomain = 'mobile.app.uni-frankfurt.de';
|
||||
|
||||
export const environment = {
|
||||
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
||||
appDomain: 'mobile.app.uni-frankfurt.de',
|
||||
backend_version: '2.0.0',
|
||||
use_fake_backend: false,
|
||||
production: false,
|
||||
oauth2: {
|
||||
client: {
|
||||
his: {
|
||||
client_id: '1cac3f99-33fa-4234-8438-979f07e0cdab',
|
||||
client_secret: '',
|
||||
server_host: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0',
|
||||
redirect_url: `https://${appDomain}/auth/callback`,
|
||||
scopes: '',
|
||||
pkce: true,
|
||||
} as IAuthConfig,
|
||||
paia: {
|
||||
client_id: '',
|
||||
client_secret: '',
|
||||
server_host:
|
||||
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
// TODO: Use Custom URL Scheme (ideally bundle ID from capacitor.config)
|
||||
redirect_url: `https://${appDomain}/auth/paia/callback`,
|
||||
scopes: '',
|
||||
// TODO: PAIA need to support PKCE, it will then work "out-of-the-box"
|
||||
pkce: true,
|
||||
} as IAuthConfig,
|
||||
},
|
||||
service: {
|
||||
his: {
|
||||
authorization_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/authorize',
|
||||
token_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/accessToken',
|
||||
userinfo_endpoint:
|
||||
'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/profile',
|
||||
} as AuthorizationServiceConfigurationJson,
|
||||
paia: {
|
||||
authorization_endpoint:
|
||||
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
|
||||
token_endpoint: 'https://hds.hebis.de:8443/auth/login',
|
||||
userinfo_endpoint: 'https://hds.hebis.de:8443/core',
|
||||
} as AuthorizationServiceConfigurationJson,
|
||||
},
|
||||
endpointMappings: {
|
||||
userinfo: {
|
||||
id: 'employeeNumber',
|
||||
given_name: 'givenName',
|
||||
family_name: 'sn',
|
||||
email: 'mailPrimaryAddress',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user