mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-04-16 19:29:05 +00:00
feat: add auth support (default and paia)
This commit is contained in:
committed by
Jovan Krunić
parent
046a95ba1d
commit
b5f239ea4e
@@ -41,7 +41,7 @@
|
|||||||
"unicorn/no-array-callback-reference": "off",
|
"unicorn/no-array-callback-reference": "off",
|
||||||
"unicorn/prefer-object-from-entries": "off",
|
"unicorn/prefer-object-from-entries": "off",
|
||||||
"unicorn/prevent-abbreviations": [
|
"unicorn/prevent-abbreviations": [
|
||||||
"error",
|
"warn",
|
||||||
{
|
{
|
||||||
"replacements": {
|
"replacements": {
|
||||||
"ref": false,
|
"ref": false,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ apply plugin: 'com.android.application'
|
|||||||
android {
|
android {
|
||||||
compileSdkVersion rootProject.ext.compileSdkVersion
|
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.any_school.app"
|
applicationId "de.anyschool.app"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 1
|
versionCode 1
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ android {
|
|||||||
|
|
||||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation project(':capacitor-community-http')
|
||||||
implementation project(':capacitor-app')
|
implementation project(':capacitor-app')
|
||||||
implementation project(':capacitor-browser')
|
implementation project(':capacitor-browser')
|
||||||
implementation project(':capacitor-haptics')
|
implementation project(':capacitor-haptics')
|
||||||
implementation project(':capacitor-keyboard')
|
implementation project(':capacitor-keyboard')
|
||||||
implementation project(':capacitor-splash-screen')
|
implementation project(':capacitor-splash-screen')
|
||||||
implementation project(':capacitor-status-bar')
|
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.legacy:legacy-support-v4:1.0.0"
|
||||||
implementation "androidx.appcompat:appcompat:1.3.1"
|
implementation "androidx.appcompat:appcompat:1.3.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +1,27 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest package="de.anyschool.app" 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" 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">
|
||||||
<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">
|
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
<intent-filter android:autoVerify="true">
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<data android:scheme="@string/custom_url_scheme" />
|
||||||
<!-- NEXT LINE'S HOST TO BE GENERATED (SCHOOL SPECIFIC) -->
|
</intent-filter>
|
||||||
<data android:scheme="https" android:host="mobile.app.uni-frankfurt.de" />
|
<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" />
|
||||||
|
<data android:host="mobile.app.uni-frankfurt.de" android:scheme="https" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
<provider android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true" android:name="androidx.core.content.FileProvider">
|
||||||
<provider
|
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
|
||||||
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>
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<!-- Permissions -->
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"appId": "de.any_school.app",
|
"appId": "de.anyschool.app",
|
||||||
"appName": "StApps",
|
"appName": "StApps",
|
||||||
"webDir": "www",
|
"webDir": "www",
|
||||||
"bundledWebRuntime": false,
|
"bundledWebRuntime": false,
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"pkg": "@capacitor-community/http",
|
||||||
|
"classpath": "com.getcapacitor.plugin.http.Http"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"pkg": "@capacitor/app",
|
"pkg": "@capacitor/app",
|
||||||
"classpath": "com.capacitorjs.plugins.app.AppPlugin"
|
"classpath": "com.capacitorjs.plugins.app.AppPlugin"
|
||||||
@@ -22,5 +26,13 @@
|
|||||||
{
|
{
|
||||||
"pkg": "@capacitor/status-bar",
|
"pkg": "@capacitor/status-bar",
|
||||||
"classpath": "com.capacitorjs.plugins.statusbar.StatusBarPlugin"
|
"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,4 +1,4 @@
|
|||||||
package de.any_school.app;
|
package de.anyschool.app;
|
||||||
|
|
||||||
import com.getcapacitor.BridgeActivity;
|
import com.getcapacitor.BridgeActivity;
|
||||||
|
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">StApps</string>
|
<string name="app_name">StApps</string>
|
||||||
<string name="title_activity_main">StApps</string>
|
<string name="title_activity_main">StApps</string>
|
||||||
<string name="package_name">de.any_school.app</string>
|
<string name="package_name">de.anyschool.app</string>
|
||||||
<string name="custom_url_scheme">de.any_school.app</string>
|
<string name="custom_url_scheme">de.anyschool.app</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
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'
|
classpath 'com.google.gms:google-services:4.3.5'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
include ':capacitor-android'
|
include ':capacitor-android'
|
||||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
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'
|
include ':capacitor-app'
|
||||||
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')
|
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'
|
include ':capacitor-status-bar'
|
||||||
project(':capacitor-status-bar').projectDir = new File('../node_modules/@capacitor/status-bar/android')
|
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,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
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
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {CapacitorConfig} from '@capacitor/cli';
|
import {CapacitorConfig} from '@capacitor/cli';
|
||||||
|
|
||||||
const config: CapacitorConfig = {
|
const config: CapacitorConfig = {
|
||||||
appId: 'de.any_school.app',
|
appId: 'de.anyschool.app',
|
||||||
appName: 'StApps',
|
appName: 'StApps',
|
||||||
webDir: 'www',
|
webDir: 'www',
|
||||||
bundledWebRuntime: false,
|
bundledWebRuntime: false,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
<?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>
|
<name>StApps</name>
|
||||||
<description>An awesome Ionic/Cordova app.</description>
|
<description>An awesome Ionic/Cordova app.</description>
|
||||||
<author email="hi@ionicframework" href="http://ionicframework.com/">Ionic Framework Team</author>
|
<author email="hi@ionicframework" href="http://ionicframework.com/">Ionic Framework Team</author>
|
||||||
@@ -21,10 +21,6 @@
|
|||||||
<preference name="SplashScreen" value="screen" />
|
<preference name="SplashScreen" value="screen" />
|
||||||
<preference name="SplashScreenDelay" value="3000" />
|
<preference name="SplashScreenDelay" value="3000" />
|
||||||
<plugin name="cordova-plugin-whitelist" spec="1.3.3" />
|
<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">
|
<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." />
|
<variable name="GEOLOCATION_USAGE_DESCRIPTION" value="The app will use your location to provide features for navigation or distances information." />
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|||||||
9
ios/.gitignore
vendored
Normal file
9
ios/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
App/build
|
||||||
|
App/Pods
|
||||||
|
App/Podfile.lock
|
||||||
|
App/App/public
|
||||||
|
DerivedData
|
||||||
|
xcuserdata
|
||||||
|
|
||||||
|
# Cordova plugins for Capacitor
|
||||||
|
capacitor-cordova-ios-plugins
|
||||||
428
ios/App/App.xcodeproj/project.pbxproj
Normal file
428
ios/App/App.xcodeproj/project.pbxproj
Normal file
@@ -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 */;
|
||||||
|
}
|
||||||
7
ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
ios/App/App.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:App.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
78
ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme
Normal file
78
ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme
Normal file
@@ -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
ios/App/App.xcworkspace/contents.xcworkspacedata
generated
Normal file
10
ios/App/App.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -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>
|
||||||
10
ios/App/App/App.entitlements
Normal file
10
ios/App/App/App.entitlements
Normal file
@@ -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>
|
||||||
60
ios/App/App/AppDelegate.swift
Normal file
60
ios/App/App/AppDelegate.swift
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
116
ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
116
ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
ios/App/App/Assets.xcassets/Contents.json
Normal file
6
ios/App/App/Assets.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
23
ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
vendored
Normal file
23
ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
vendored
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
32
ios/App/App/Base.lproj/LaunchScreen.storyboard
Normal file
32
ios/App/App/Base.lproj/LaunchScreen.storyboard
Normal file
@@ -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>
|
||||||
19
ios/App/App/Base.lproj/Main.storyboard
Normal file
19
ios/App/App/Base.lproj/Main.storyboard
Normal file
@@ -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>
|
||||||
68
ios/App/App/Info.plist
Normal file
68
ios/App/App/Info.plist
Normal file
@@ -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>
|
||||||
19
ios/App/App/capacitor.config.json
Normal file
19
ios/App/App/capacitor.config.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
ios/App/App/config.xml
Normal file
86
ios/App/App/config.xml
Normal file
@@ -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>
|
||||||
28
ios/App/Podfile
Normal file
28
ios/App/Podfile
Normal file
@@ -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
|
||||||
238
package-lock.json
generated
238
package-lock.json
generated
@@ -2067,11 +2067,21 @@
|
|||||||
"to-fast-properties": "^2.0.0"
|
"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": {
|
"@capacitor/android": {
|
||||||
"version": "3.3.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-3.4.0.tgz",
|
||||||
"integrity": "sha512-TG+tGz0KxkT/BgvSLQfbQwQ9c4Budub5TRijIGdmMbB1ZYB76TFhwvVuwWZ52HFSlKS3sx/UYLlbULL7UQ2aug==",
|
"integrity": "sha512-O2hHGVzdTH2Lsmz58EI8zHY5byEFIWl9KrW60WSrO/tV6u9DpfaUq56FaejvfU27GFXDZkmoQNa33EvDYWp4wA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@capacitor/app": {
|
"@capacitor/app": {
|
||||||
"version": "1.0.6",
|
"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": {
|
"@capacitor/haptics": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-1.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/haptics/-/haptics-1.1.3.tgz",
|
||||||
@@ -2160,8 +2175,7 @@
|
|||||||
"@capacitor/ios": {
|
"@capacitor/ios": {
|
||||||
"version": "3.3.2",
|
"version": "3.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/ios/-/ios-3.3.2.tgz",
|
||||||
"integrity": "sha512-qXbWo9zTtinIYDxKsLdkXXuZD8H+wlJII3+ZF9QzH+38IYyd+sohOG3NLC8EaX7GRtwCymd+mGotoN420SfQ4Q==",
|
"integrity": "sha512-qXbWo9zTtinIYDxKsLdkXXuZD8H+wlJII3+ZF9QzH+38IYyd+sohOG3NLC8EaX7GRtwCymd+mGotoN420SfQ4Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"@capacitor/keyboard": {
|
"@capacitor/keyboard": {
|
||||||
"version": "1.1.3",
|
"version": "1.1.3",
|
||||||
@@ -2178,6 +2192,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-1.0.6.tgz",
|
||||||
"integrity": "sha512-5MGWFq76iiKvHpbZ/Xc0Zig3WZyzWZ62wvC4qxak8OuVHBNG4fA1p/XXY9teQPaU3SupEJHnLkw6Gn1LuDp+ew=="
|
"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": {
|
"@compodoc/compodoc": {
|
||||||
"version": "1.1.14",
|
"version": "1.1.14",
|
||||||
"resolved": "https://registry.npmjs.org/@compodoc/compodoc/-/compodoc-1.1.14.tgz",
|
"resolved": "https://registry.npmjs.org/@compodoc/compodoc/-/compodoc-1.1.14.tgz",
|
||||||
@@ -2532,6 +2551,40 @@
|
|||||||
"@types/cordova": "^0.0.34"
|
"@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": {
|
"@ionic-native/network": {
|
||||||
"version": "5.36.0",
|
"version": "5.36.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic-native/network/-/network-5.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ionic-native/network/-/network-5.36.0.tgz",
|
||||||
@@ -2540,6 +2593,40 @@
|
|||||||
"@types/cordova": "^0.0.34"
|
"@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": {
|
"@ionic/angular": {
|
||||||
"version": "5.7.0",
|
"version": "5.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-5.7.0.tgz",
|
"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": {
|
"@openstapps/api": {
|
||||||
"version": "0.35.0",
|
"version": "0.35.0",
|
||||||
"resolved": "https://registry.npmjs.org/@openstapps/api/-/api-0.35.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
|
||||||
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA=="
|
"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": {
|
"@types/body-parser": {
|
||||||
"version": "1.19.2",
|
"version": "1.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
|
||||||
@@ -3698,6 +3815,14 @@
|
|||||||
"@types/jasmine": "*"
|
"@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": {
|
"@types/json-patch": {
|
||||||
"version": "0.0.30",
|
"version": "0.0.30",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-patch/-/json-patch-0.0.30.tgz",
|
"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": {
|
"@types/source-list-map": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
|
||||||
@@ -5108,8 +5238,7 @@
|
|||||||
"base64-js": {
|
"base64-js": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"base64id": {
|
"base64id": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@@ -5315,6 +5444,11 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"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",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"get-intrinsic": "^1.0.2"
|
"get-intrinsic": "^1.0.2"
|
||||||
@@ -5704,6 +5837,14 @@
|
|||||||
"integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
|
"integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
|
||||||
"dev": true
|
"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": {
|
"caseless": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||||
@@ -8770,6 +8911,11 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"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",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
||||||
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"function-bind": "^1.1.1",
|
"function-bind": "^1.1.1",
|
||||||
"has": "^1.0.3",
|
"has": "^1.0.3",
|
||||||
@@ -9579,6 +9724,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
|
||||||
"integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ=="
|
"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": {
|
"handle-thing": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||||
@@ -9661,8 +9811,7 @@
|
|||||||
"has-symbols": {
|
"has-symbols": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
|
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"has-tostringtag": {
|
"has-tostringtag": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -10307,6 +10456,33 @@
|
|||||||
"ipaddr.js": "^1.9.0"
|
"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": {
|
"ionicons": {
|
||||||
"version": "5.5.4",
|
"version": "5.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-5.5.4.tgz",
|
||||||
@@ -11069,6 +11245,11 @@
|
|||||||
"integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
|
"integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
|
||||||
"dev": true
|
"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": {
|
"jsonpointer": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.1.0.tgz",
|
||||||
@@ -12882,8 +13063,7 @@
|
|||||||
"object-inspect": {
|
"object-inspect": {
|
||||||
"version": "1.11.0",
|
"version": "1.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
|
||||||
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==",
|
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"object-is": {
|
"object-is": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
@@ -12997,6 +13177,11 @@
|
|||||||
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
|
"integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
|
||||||
"dev": true
|
"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": {
|
"opening_hours": {
|
||||||
"version": "3.7.0",
|
"version": "3.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/opening_hours/-/opening_hours-3.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/opening_hours/-/opening_hours-3.7.0.tgz",
|
||||||
@@ -15413,9 +15598,12 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.7.0",
|
"version": "6.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
|
||||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
"integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
|
||||||
|
"requires": {
|
||||||
|
"side-channel": "^1.0.4"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"querystring": {
|
"querystring": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
@@ -16147,9 +16335,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rxjs": {
|
"rxjs": {
|
||||||
"version": "6.6.3",
|
"version": "6.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
|
||||||
"integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
|
"integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^1.9.0"
|
"tslib": "^1.9.0"
|
||||||
},
|
},
|
||||||
@@ -16547,6 +16735,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
|
||||||
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
|
"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": {
|
"signal-exit": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -54,6 +54,7 @@
|
|||||||
"@angular/router": "12.2.13",
|
"@angular/router": "12.2.13",
|
||||||
"@asymmetrik/ngx-leaflet": "8.1.0",
|
"@asymmetrik/ngx-leaflet": "8.1.0",
|
||||||
"@asymmetrik/ngx-leaflet-markercluster": "5.0.1",
|
"@asymmetrik/ngx-leaflet-markercluster": "5.0.1",
|
||||||
|
"@capacitor-community/http": "1.4.1",
|
||||||
"@capacitor/app": "1.0.6",
|
"@capacitor/app": "1.0.6",
|
||||||
"@capacitor/browser": "1.0.6",
|
"@capacitor/browser": "1.0.6",
|
||||||
"@capacitor/core": "3.3.1",
|
"@capacitor/core": "3.3.1",
|
||||||
@@ -61,6 +62,7 @@
|
|||||||
"@capacitor/keyboard": "1.1.3",
|
"@capacitor/keyboard": "1.1.3",
|
||||||
"@capacitor/splash-screen": "1.1.6",
|
"@capacitor/splash-screen": "1.1.6",
|
||||||
"@capacitor/status-bar": "1.0.6",
|
"@capacitor/status-bar": "1.0.6",
|
||||||
|
"@capacitor/storage": "1.2.3",
|
||||||
"@ionic-native/core": "5.36.0",
|
"@ionic-native/core": "5.36.0",
|
||||||
"@ionic-native/diagnostic": "5.36.0",
|
"@ionic-native/diagnostic": "5.36.0",
|
||||||
"@ionic-native/dialogs": "5.36.0",
|
"@ionic-native/dialogs": "5.36.0",
|
||||||
@@ -73,6 +75,7 @@
|
|||||||
"@openstapps/api": "0.35.0",
|
"@openstapps/api": "0.35.0",
|
||||||
"@openstapps/configuration": "0.28.1",
|
"@openstapps/configuration": "0.28.1",
|
||||||
"@openstapps/core": "0.53.0",
|
"@openstapps/core": "0.53.0",
|
||||||
|
"capacitor-secure-storage-plugin": "0.6.2",
|
||||||
"cordova-plugin-device": "2.0.3",
|
"cordova-plugin-device": "2.0.3",
|
||||||
"cordova-plugin-dialogs": "2.0.2",
|
"cordova-plugin-dialogs": "2.0.2",
|
||||||
"cordova-plugin-geolocation": "4.1.0",
|
"cordova-plugin-geolocation": "4.1.0",
|
||||||
@@ -83,6 +86,8 @@
|
|||||||
"deepmerge": "3.3.0",
|
"deepmerge": "3.3.0",
|
||||||
"form-data": "2.5.0",
|
"form-data": "2.5.0",
|
||||||
"geojson": "0.5.0",
|
"geojson": "0.5.0",
|
||||||
|
"ionic-appauth": "0.8.5",
|
||||||
|
"jsonpath-plus": "6.0.1",
|
||||||
"leaflet": "1.7.1",
|
"leaflet": "1.7.1",
|
||||||
"leaflet.markercluster": "1.5.1",
|
"leaflet.markercluster": "1.5.1",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
@@ -91,7 +96,8 @@
|
|||||||
"ngx-markdown": "12.0.1",
|
"ngx-markdown": "12.0.1",
|
||||||
"ngx-moment": "5.0.0",
|
"ngx-moment": "5.0.0",
|
||||||
"opening_hours": "3.7.0",
|
"opening_hours": "3.7.0",
|
||||||
"rxjs": "6.6.3",
|
"qs": "6.10.1",
|
||||||
|
"rxjs": "6.6.7",
|
||||||
"swiper": "7.1.0",
|
"swiper": "7.1.0",
|
||||||
"tslib": "2.0.0",
|
"tslib": "2.0.0",
|
||||||
"zone.js": "0.11.4"
|
"zone.js": "0.11.4"
|
||||||
@@ -110,7 +116,7 @@
|
|||||||
"@angular/compiler": "12.2.13",
|
"@angular/compiler": "12.2.13",
|
||||||
"@angular/compiler-cli": "12.2.13",
|
"@angular/compiler-cli": "12.2.13",
|
||||||
"@angular/language-service": "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/cli": "3.3.2",
|
||||||
"@capacitor/ios": "3.3.2",
|
"@capacitor/ios": "3.3.2",
|
||||||
"@compodoc/compodoc": "1.1.14",
|
"@compodoc/compodoc": "1.1.14",
|
||||||
@@ -123,6 +129,7 @@
|
|||||||
"@types/leaflet.markercluster": "1.4.5",
|
"@types/leaflet.markercluster": "1.4.5",
|
||||||
"@types/lodash-es": "4.17.4",
|
"@types/lodash-es": "4.17.4",
|
||||||
"@types/node": "14.17.16",
|
"@types/node": "14.17.16",
|
||||||
|
"@types/qs": "6.9.7",
|
||||||
"@typescript-eslint/eslint-plugin": "4.32.0",
|
"@typescript-eslint/eslint-plugin": "4.32.0",
|
||||||
"@typescript-eslint/parser": "4.32.0",
|
"@typescript-eslint/parser": "4.32.0",
|
||||||
"conventional-changelog-cli": "2.1.1",
|
"conventional-changelog-cli": "2.1.1",
|
||||||
|
|||||||
@@ -30478,7 +30478,7 @@ export const sampleResources = [{
|
|||||||
'steps': [
|
'steps': [
|
||||||
{
|
{
|
||||||
'type': 'location',
|
'type': 'location',
|
||||||
'location': '#/b-tu/main'
|
'location': '/b-tu/main'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'type': 'tooltip',
|
'type': 'tooltip',
|
||||||
@@ -30494,7 +30494,7 @@ export const sampleResources = [{
|
|||||||
'text': 'Öffne die Suche.',
|
'text': 'Öffne die Suche.',
|
||||||
'resolved': {
|
'resolved': {
|
||||||
'location': {
|
'location': {
|
||||||
'is': '#/b-tu/search'
|
'is': '/b-tu/search'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'position': 'bottom'
|
'position': 'bottom'
|
||||||
@@ -30529,7 +30529,7 @@ export const sampleResources = [{
|
|||||||
'text': 'Klicke auf eine Veranstaltung...',
|
'text': 'Klicke auf eine Veranstaltung...',
|
||||||
'resolved': {
|
'resolved': {
|
||||||
'location': {
|
'location': {
|
||||||
'match': '#/b-tu/data/detail/Event'
|
'match': '/b-tu/data/detail/Event'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'position': 'top'
|
'position': 'top'
|
||||||
@@ -30553,7 +30553,7 @@ export const sampleResources = [{
|
|||||||
'text': 'Öffne deinen Stundenplan.',
|
'text': 'Öffne deinen Stundenplan.',
|
||||||
'resolved': {
|
'resolved': {
|
||||||
'location': {
|
'location': {
|
||||||
'is': '#/b-tu/events'
|
'is': '/b-tu/events'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'position': 'right'
|
'position': 'right'
|
||||||
@@ -30585,7 +30585,7 @@ export const sampleResources = [{
|
|||||||
'steps': [
|
'steps': [
|
||||||
{
|
{
|
||||||
'type': 'location',
|
'type': 'location',
|
||||||
'location': '#/b-tu/main'
|
'location': '/b-tu/main'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'type': 'tooltip',
|
'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.',
|
'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': {
|
'resolved': {
|
||||||
'location': {
|
'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.',
|
'text': 'Wähle die "Mathe Cafeteria" aus, um sie zu favorisieren.',
|
||||||
'resolved': {
|
'resolved': {
|
||||||
'location': {
|
'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.',
|
'text': 'Klicke auf das TU-Logo oder "StApps", um zur Startseite zurückzukehren.',
|
||||||
'resolved': {
|
'resolved': {
|
||||||
'location': {
|
'location': {
|
||||||
'is': '#/b-tu/main'
|
'is': '/b-tu/main'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -30691,7 +30691,7 @@ export const sampleResources = [{
|
|||||||
'text': 'Öffne deine Favoriten.',
|
'text': 'Öffne deine Favoriten.',
|
||||||
'resolved': {
|
'resolved': {
|
||||||
'location': {
|
'location': {
|
||||||
'is': '#/b-tu/favorites'
|
'is': '/b-tu/favorites'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {NgModule} from '@angular/core';
|
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'}];
|
const routes: Routes = [{path: '', redirectTo: '/news', pathMatch: 'full'}];
|
||||||
|
|
||||||
@@ -22,6 +22,11 @@ const routes: Routes = [{path: '', redirectTo: '/news', pathMatch: 'full'}];
|
|||||||
*/
|
*/
|
||||||
@NgModule({
|
@NgModule({
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
imports: [RouterModule.forRoot(routes, {relativeLinkResolution: 'legacy'})],
|
imports: [
|
||||||
|
RouterModule.forRoot(routes, {
|
||||||
|
enableTracing: true,
|
||||||
|
preloadingStrategy: PreloadAllModules,
|
||||||
|
}),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class AppRoutingModule {}
|
export class AppRoutingModule {}
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ import {Platform} from '@ionic/angular';
|
|||||||
|
|
||||||
import {TranslateService} from '@ngx-translate/core';
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
import {ThingTranslateService} from './translation/thing-translate.service';
|
import {ThingTranslateService} from './translation/thing-translate.service';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
|
import {AuthModule} from './modules/auth/auth.module';
|
||||||
import {ConfigProvider} from './modules/config/config.provider';
|
import {ConfigProvider} from './modules/config/config.provider';
|
||||||
import {SettingsProvider} from './modules/settings/settings.provider';
|
import {SettingsProvider} from './modules/settings/settings.provider';
|
||||||
import {NGXLogger} from 'ngx-logger';
|
import {NGXLogger} from 'ngx-logger';
|
||||||
@@ -35,10 +37,16 @@ describe('AppComponent', () => {
|
|||||||
let configProvider: jasmine.SpyObj<ConfigProvider>;
|
let configProvider: jasmine.SpyObj<ConfigProvider>;
|
||||||
let ngxLogger: jasmine.SpyObj<NGXLogger>;
|
let ngxLogger: jasmine.SpyObj<NGXLogger>;
|
||||||
|
|
||||||
|
let platformIsSpy;
|
||||||
|
|
||||||
beforeEach(
|
beforeEach(
|
||||||
waitForAsync(() => {
|
waitForAsync(() => {
|
||||||
platformReadySpy = Promise.resolve();
|
platformReadySpy = Promise.resolve();
|
||||||
platformSpy = jasmine.createSpyObj('Platform', {ready: platformReadySpy});
|
platformIsSpy = Promise.resolve();
|
||||||
|
platformSpy = jasmine.createSpyObj('Platform', {
|
||||||
|
ready: platformReadySpy,
|
||||||
|
is: platformIsSpy,
|
||||||
|
});
|
||||||
translateServiceSpy = jasmine.createSpyObj('TranslateService', [
|
translateServiceSpy = jasmine.createSpyObj('TranslateService', [
|
||||||
'setDefaultLang',
|
'setDefaultLang',
|
||||||
'use',
|
'use',
|
||||||
@@ -55,7 +63,11 @@ describe('AppComponent', () => {
|
|||||||
ngxLogger = jasmine.createSpyObj('NGXLogger', ['log', 'error', 'warn']);
|
ngxLogger = jasmine.createSpyObj('NGXLogger', ['log', 'error', 'warn']);
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [RouterTestingModule.withRoutes([])],
|
imports: [
|
||||||
|
RouterTestingModule.withRoutes([]),
|
||||||
|
HttpClientTestingModule,
|
||||||
|
AuthModule,
|
||||||
|
],
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: Platform, useValue: platformSpy},
|
{provide: Platform, useValue: platformSpy},
|
||||||
|
|||||||
@@ -16,10 +16,14 @@ import {Component, NgZone} from '@angular/core';
|
|||||||
import {Router} from '@angular/router';
|
import {Router} from '@angular/router';
|
||||||
import {App, URLOpenListenerEvent} from '@capacitor/app';
|
import {App, URLOpenListenerEvent} from '@capacitor/app';
|
||||||
import {SplashScreen} from '@capacitor/splash-screen';
|
import {SplashScreen} from '@capacitor/splash-screen';
|
||||||
import {Platform} from '@ionic/angular';
|
import {Platform, ToastController} from '@ionic/angular';
|
||||||
import {NGXLogger} from 'ngx-logger';
|
import {NGXLogger} from 'ngx-logger';
|
||||||
import {ConfigProvider} from './modules/config/config.provider';
|
import {ConfigProvider} from './modules/config/config.provider';
|
||||||
import {SettingsProvider} from './modules/settings/settings.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
|
* TODO
|
||||||
@@ -51,6 +55,10 @@ export class AppComponent {
|
|||||||
* @param logger An angular logger
|
* @param logger An angular logger
|
||||||
* @param router The angular router
|
* @param router The angular router
|
||||||
* @param zone The angular zone
|
* @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(
|
constructor(
|
||||||
private readonly platform: Platform,
|
private readonly platform: Platform,
|
||||||
@@ -59,6 +67,10 @@ export class AppComponent {
|
|||||||
private readonly logger: NGXLogger,
|
private readonly logger: NGXLogger,
|
||||||
private readonly router: Router,
|
private readonly router: Router,
|
||||||
private readonly zone: NgZone,
|
private readonly zone: NgZone,
|
||||||
|
private readonly defaultAuth: DefaultAuthService,
|
||||||
|
private readonly paiaAuth: PAIAAuthService,
|
||||||
|
private readonly authHelperService: AuthHelperService,
|
||||||
|
private readonly toastController: ToastController,
|
||||||
) {
|
) {
|
||||||
void this.initializeApp();
|
void this.initializeApp();
|
||||||
}
|
}
|
||||||
@@ -69,7 +81,7 @@ export class AppComponent {
|
|||||||
async initializeApp() {
|
async initializeApp() {
|
||||||
App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {
|
App.addListener('appUrlOpen', (event: URLOpenListenerEvent) => {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
const slug = event.url.split('.de').pop();
|
const slug = event.url.split(environment.appDomain).pop();
|
||||||
if (slug) {
|
if (slug) {
|
||||||
this.router.navigateByUrl(slug);
|
this.router.navigateByUrl(slug);
|
||||||
}
|
}
|
||||||
@@ -78,6 +90,9 @@ export class AppComponent {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.platform.ready().then(async () => {
|
this.platform.ready().then(async () => {
|
||||||
|
await this.authInit();
|
||||||
|
await this.defaultAuth.init();
|
||||||
|
await this.paiaAuth.init();
|
||||||
await SplashScreen.hide();
|
await SplashScreen.hide();
|
||||||
|
|
||||||
// initialise the configProvider
|
// 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,
|
PathLocationStrategy,
|
||||||
registerLocaleData,
|
registerLocaleData,
|
||||||
} from '@angular/common';
|
} from '@angular/common';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||||
import localeDe from '@angular/common/locales/de';
|
import localeDe from '@angular/common/locales/de';
|
||||||
import {APP_INITIALIZER, NgModule, Provider} from '@angular/core';
|
import {APP_INITIALIZER, NgModule, Provider} from '@angular/core';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
@@ -55,10 +55,13 @@ import {initLogger} from './_helpers/ts-logger';
|
|||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
import {AboutModule} from './modules/about/about.module';
|
import {AboutModule} from './modules/about/about.module';
|
||||||
import {FavoritesModule} from './modules/favorites/favorites.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 {FeedbackModule} from './modules/feedback/feedback.module';
|
||||||
import {DebugDataCollectorService} from './modules/data/debug-data-collector.service';
|
import {DebugDataCollectorService} from './modules/data/debug-data-collector.service';
|
||||||
import {Browser} from './util/browser.factory';
|
import {Browser} from './util/browser.factory';
|
||||||
import {browserFactory} from './util/browser.factory';
|
import {browserFactory} from './util/browser.factory';
|
||||||
|
import {AuthModule} from './modules/auth/auth.module';
|
||||||
|
|
||||||
registerLocaleData(localeDe);
|
registerLocaleData(localeDe);
|
||||||
|
|
||||||
@@ -143,14 +146,18 @@ const providers: Provider[] = [
|
|||||||
imports: [
|
imports: [
|
||||||
AboutModule,
|
AboutModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
|
AuthModule,
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
CatalogModule,
|
CatalogModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
ConfigModule,
|
ConfigModule,
|
||||||
DataModule,
|
DataModule,
|
||||||
|
EndSessionPageModule,
|
||||||
IonicModule.forRoot(),
|
IonicModule.forRoot(),
|
||||||
FavoritesModule,
|
FavoritesModule,
|
||||||
|
HttpClientModule,
|
||||||
|
ProfilePageModule,
|
||||||
FeedbackModule,
|
FeedbackModule,
|
||||||
MapModule,
|
MapModule,
|
||||||
MenuModule,
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/app/modules/auth/auth-guard.service.ts
Normal file
42
src/app/modules/auth/auth-guard.service.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/app/modules/auth/auth-helper.service.ts
Normal file
50
src/app/modules/auth/auth-helper.service.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/app/modules/auth/auth-routes.ts
Normal file
31
src/app/modules/auth/auth-routes.ts
Normal file
@@ -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[];
|
||||||
33
src/app/modules/auth/auth-routing.module.ts
Normal file
33
src/app/modules/auth/auth-routing.module.ts
Normal file
@@ -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 {}
|
||||||
47
src/app/modules/auth/auth.module.ts
Normal file
47
src/app/modules/auth/auth.module.ts
Normal file
@@ -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 {}
|
||||||
53
src/app/modules/auth/capacitor-requestor.ts
Normal file
53
src/app/modules/auth/capacitor-requestor.ts
Normal file
@@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
53
src/app/modules/auth/default-auth.service.ts
Normal file
53
src/app/modules/auth/default-auth.service.ts
Normal file
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/app/modules/auth/end-session/end-session.module.ts
Normal file
26
src/app/modules/auth/end-session/end-session.module.ts
Normal file
@@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/app/modules/auth/factories/auth.factory.ts
Normal file
52
src/app/modules/auth/factories/auth.factory.ts
Normal file
@@ -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;
|
||||||
|
};
|
||||||
9
src/app/modules/auth/factories/browser.factory.ts
Normal file
9
src/app/modules/auth/factories/browser.factory.ts
Normal file
@@ -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();
|
||||||
|
};
|
||||||
10
src/app/modules/auth/factories/http.factory.ts
Normal file
10
src/app/modules/auth/factories/http.factory.ts
Normal file
@@ -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);
|
||||||
|
};
|
||||||
3
src/app/modules/auth/factories/index.ts
Normal file
3
src/app/modules/auth/factories/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './auth.factory';
|
||||||
|
export * from './browser.factory';
|
||||||
|
export * from './storage.factory';
|
||||||
9
src/app/modules/auth/factories/storage.factory.ts
Normal file
9
src/app/modules/auth/factories/storage.factory.ts
Normal file
@@ -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();
|
||||||
|
};
|
||||||
53
src/app/modules/auth/ng-http.service.ts
Normal file
53
src/app/modules/auth/ng-http.service.ts
Normal file
@@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
217
src/app/modules/auth/paia/authorization-request-handler.ts
Normal file
217
src/app/modules/auth/paia/authorization-request-handler.ts
Normal file
@@ -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`;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/app/modules/auth/paia/authorization-request-response.ts
Normal file
26
src/app/modules/auth/paia/authorization-request-response.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
85
src/app/modules/auth/paia/paia-auth-action.ts
Normal file
85
src/app/modules/auth/paia/paia-auth-action.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
342
src/app/modules/auth/paia/paia-auth.service.ts
Normal file
342
src/app/modules/auth/paia/paia-auth.service.ts
Normal file
@@ -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');
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/app/modules/auth/paia/paia-authorization-listener.ts
Normal file
23
src/app/modules/auth/paia/paia-authorization-listener.ts
Normal file
@@ -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;
|
||||||
40
src/app/modules/auth/paia/paia-authorization-notifier.ts
Normal file
40
src/app/modules/auth/paia/paia-authorization-notifier.ts
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/app/modules/auth/paia/paia-authorization-response.ts
Normal file
38
src/app/modules/auth/paia/paia-authorization-response.ts
Normal file
@@ -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};
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/app/modules/auth/paia/paia-token-request.ts
Normal file
65
src/app/modules/auth/paia/paia-token-request.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/app/modules/auth/paia/paia-token-response.ts
Normal file
54
src/app/modules/auth/paia/paia-token-response.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/app/modules/auth/paia/paia-user-info-handler.ts
Normal file
44
src/app/modules/auth/paia/paia-user-info-handler.ts
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
84
src/app/modules/auth/paia/token-request-handler.ts
Normal file
84
src/app/modules/auth/paia/token-request-handler.ts
Normal file
@@ -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)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/app/modules/auth/user-info.model.ts
Normal file
21
src/app/modules/auth/user-info.model.ts
Normal file
@@ -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
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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 {LangChangeEvent, TranslateService} from '@ngx-translate/core';
|
||||||
import {
|
import {
|
||||||
SCAppConfigurationMenuCategory,
|
SCAppConfigurationMenuCategory,
|
||||||
@@ -20,8 +20,7 @@ import {
|
|||||||
SCThingTranslator,
|
SCThingTranslator,
|
||||||
SCTranslations,
|
SCTranslations,
|
||||||
} from '@openstapps/core';
|
} from '@openstapps/core';
|
||||||
import {NGXLogger} from 'ngx-logger';
|
import {NavigationService} from './navigation.service';
|
||||||
import {ConfigProvider} from '../../config/config.provider';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generated class for the MenuPage page.
|
* Generated class for the MenuPage page.
|
||||||
@@ -34,7 +33,7 @@ import {ConfigProvider} from '../../config/config.provider';
|
|||||||
styleUrls: ['navigation.scss'],
|
styleUrls: ['navigation.scss'],
|
||||||
templateUrl: 'navigation.html',
|
templateUrl: 'navigation.html',
|
||||||
})
|
})
|
||||||
export class NavigationComponent {
|
export class NavigationComponent implements OnInit {
|
||||||
/**
|
/**
|
||||||
* Possible languages to be used for translation
|
* Possible languages to be used for translation
|
||||||
*/
|
*/
|
||||||
@@ -60,11 +59,9 @@ export class NavigationComponent {
|
|||||||
translator: SCThingTranslator;
|
translator: SCThingTranslator;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly configProvider: ConfigProvider,
|
|
||||||
public translateService: TranslateService,
|
public translateService: TranslateService,
|
||||||
private readonly logger: NGXLogger,
|
private navigationService: NavigationService,
|
||||||
) {
|
) {
|
||||||
void this.loadMenuEntries();
|
|
||||||
translateService.onLangChange.subscribe((event: LangChangeEvent) => {
|
translateService.onLangChange.subscribe((event: LangChangeEvent) => {
|
||||||
this.language = event.lang as keyof SCTranslations<SCLanguage>;
|
this.language = event.lang as keyof SCTranslations<SCLanguage>;
|
||||||
this.translator = new SCThingTranslator(this.language);
|
this.translator = new SCThingTranslator(this.language);
|
||||||
@@ -72,20 +69,7 @@ export class NavigationComponent {
|
|||||||
this.translator = new SCThingTranslator('en');
|
this.translator = new SCThingTranslator('en');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async ngOnInit() {
|
||||||
* Loads menu entries from configProvider
|
this.menu = await this.navigationService.getMenu();
|
||||||
*/
|
|
||||||
async loadMenuEntries() {
|
|
||||||
try {
|
|
||||||
this.menu = (await this.configProvider.getValue(
|
|
||||||
'menus',
|
|
||||||
)) as SCAppConfigurationMenuCategory[];
|
|
||||||
} catch (error) {
|
|
||||||
this.logger.error(`error from loading menu entries: ${error}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// openPage(page) {
|
|
||||||
// this.nav.setRoot(page.component);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/app/modules/menu/navigation/navigation.service.ts
Normal file
40
src/app/modules/menu/navigation/navigation.service.ts
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
75
src/app/modules/profile/page/profile-page.component.html
Normal file
75
src/app/modules/profile/page/profile-page.component.html
Normal file
@@ -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>
|
||||||
25
src/app/modules/profile/page/profile-page.component.scss
Normal file
25
src/app/modules/profile/page/profile-page.component.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/app/modules/profile/page/profile-page.component.spec.ts
Normal file
50
src/app/modules/profile/page/profile-page.component.spec.ts
Normal file
@@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
105
src/app/modules/profile/page/profile-page.component.ts
Normal file
105
src/app/modules/profile/page/profile-page.component.ts
Normal file
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/app/modules/profile/profile.module.ts
Normal file
26
src/app/modules/profile/profile.module.ts
Normal file
@@ -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 {}
|
||||||
82
src/app/modules/profile/user.ts
Normal file
82
src/app/modules/profile/user.ts
Normal file
@@ -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."
|
"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": {
|
"common": {
|
||||||
"openingHours": {
|
"openingHours": {
|
||||||
"closed_until": "Geschlossen bis",
|
"closed_until": "Geschlossen bis",
|
||||||
@@ -202,6 +216,21 @@
|
|||||||
"pastEvent": "Event ist vorbei"
|
"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": {
|
"settings": {
|
||||||
"resetAlert.title": "Alle Einstellungen zurücksetzen?",
|
"resetAlert.title": "Alle Einstellungen zurücksetzen?",
|
||||||
"resetAlert.message": "Sind Sie sich sicher, alle Einstellungen auf ihre Anfangswerte zurückzusetzen?",
|
"resetAlert.message": "Sind Sie sich sicher, alle Einstellungen auf ihre Anfangswerte zurückzusetzen?",
|
||||||
|
|||||||
@@ -13,6 +13,20 @@
|
|||||||
"UNKNOWN": "Unknown problem."
|
"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": {
|
"common": {
|
||||||
"openingHours": {
|
"openingHours": {
|
||||||
"closed_until": "Closed until",
|
"closed_until": "Closed until",
|
||||||
@@ -202,6 +216,22 @@
|
|||||||
"pastEvent": "Event is over"
|
"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": {
|
"settings": {
|
||||||
"resetAlert.title": "Reset all settings?",
|
"resetAlert.title": "Reset all settings?",
|
||||||
"resetAlert.message": "Are you sure to reset all settings to their default values?",
|
"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
|
* 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
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -12,9 +12,74 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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 = {
|
export const environment = {
|
||||||
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
||||||
|
appDomain: 'mobile.app.uni-frankfurt.de',
|
||||||
backend_version: '2.0.0',
|
backend_version: '2.0.0',
|
||||||
use_fake_backend: true,
|
use_fake_backend: true,
|
||||||
production: false,
|
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
|
* 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
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -12,10 +12,74 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* 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 = {
|
export const environment = {
|
||||||
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
||||||
|
appDomain: 'mobile.app.uni-frankfurt.de',
|
||||||
backend_version: '2.0.0',
|
backend_version: '2.0.0',
|
||||||
use_fake_backend: false,
|
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
|
* 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
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -16,11 +16,65 @@
|
|||||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
// 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.
|
// `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`.
|
// 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 = {
|
export const environment = {
|
||||||
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
backend_url: 'https://mobile.server.uni-frankfurt.de',
|
||||||
|
appDomain: 'mobile.app.uni-frankfurt.de',
|
||||||
backend_version: '2.0.0',
|
backend_version: '2.0.0',
|
||||||
use_fake_backend: false,
|
use_fake_backend: false,
|
||||||
production: 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