Update axios requests to nativeHttp, add openid connect auth button

This commit is contained in:
advplyr 2023-09-25 17:30:39 -05:00
parent 00bed39733
commit 46f558d6e0
14 changed files with 128 additions and 14 deletions

View file

@ -36,6 +36,9 @@ android {
versionCode 97
versionName "0.9.66-beta"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders = [
"appAuthRedirectScheme": "com.audiobookshelf.app"
]
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61

View file

@ -2,13 +2,14 @@
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
}
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
dependencies {
implementation project(':byteowls-capacitor-oauth2')
implementation project(':capacitor-app')
implementation project(':capacitor-clipboard')
implementation project(':capacitor-dialog')

View file

@ -0,0 +1,14 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="app_name">audiobookshelf</string>
<string name="title_activity_main">audiobookshelf</string>
<string name="package_name">com.audiobookshelf.app</string>
<string name="custom_url_scheme">com.audiobookshelf.app.debug</string>
<string name="add_widget">Add widget</string>
<string name="app_widget_description">Simple widget for audiobookshelf playback</string>
<string name="action_jump_forward">Jump Forward</string>
<string name="action_jump_backward">Jump Backward</string>
<string name="action_skip_forward">Skip Forward</string>
<string name="action_skip_backward">Skip Backward</string>
<string name="action_change_speed">Change Playback Speed</string>
</resources>

View file

@ -1,4 +1,8 @@
[
{
"pkg": "@byteowls/capacitor-oauth2",
"classpath": "com.byteowls.capacitor.oauth2.OAuth2ClientPlugin"
},
{
"pkg": "@capacitor/app",
"classpath": "com.capacitorjs.plugins.app.AppPlugin"

View file

@ -2,6 +2,9 @@
include ':capacitor-android'
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
include ':byteowls-capacitor-oauth2'
project(':byteowls-capacitor-oauth2').projectDir = new File('../node_modules/@byteowls/capacitor-oauth2/android')
include ':capacitor-app'
project(':capacitor-app').projectDir = new File('../node_modules/@capacitor/app/android')

View file

@ -41,7 +41,7 @@
<span v-if="!serverConfig.id" class="material-icons" style="font-size: 1.1rem" @click="editServerAddress">edit</span>
</div>
<div class="w-full h-px bg-white bg-opacity-10 my-2" />
<form @submit.prevent="submitAuth" class="pt-3">
<form v-if="isLocalAuthEnabled" @submit.prevent="submitAuth" class="pt-3">
<ui-text-input v-model="serverConfig.username" :disabled="processing" placeholder="username" class="w-full mb-2 text-lg" />
<ui-text-input v-model="password" type="password" :disabled="processing" placeholder="password" class="w-full mb-2 text-lg" />
@ -51,6 +51,8 @@
<ui-btn :disabled="processing || !networkConnected" type="submit" class="mt-1 h-10">{{ networkConnected ? 'Submit' : 'No Internet' }}</ui-btn>
</div>
</form>
<div v-if="isLocalAuthEnabled && isOpenIDAuthEnabled" class="w-full h-px bg-white bg-opacity-10 my-2" />
<ui-btn v-if="isOpenIDAuthEnabled" :disabled="processing" class="mt-1 h-10" @click="clickLoginWithOpenId">Login with OpenId</ui-btn>
</template>
</div>
@ -78,6 +80,7 @@
<script>
import { Dialog } from '@capacitor/dialog'
import { CapacitorHttp } from '@capacitor/core'
import { OAuth2Client } from '@byteowls/capacitor-oauth2'
export default {
data() {
@ -93,7 +96,8 @@ export default {
password: null,
error: null,
showForm: false,
showAddCustomHeaders: false
showAddCustomHeaders: false,
authMethods: []
}
},
computed: {
@ -116,9 +120,51 @@ export default {
numCustomHeaders() {
if (!this.serverConfig.customHeaders) return 0
return Object.keys(this.serverConfig.customHeaders).length
},
isLocalAuthEnabled() {
return this.authMethods.includes('local') || !this.authMethods.length
},
isOpenIDAuthEnabled() {
return this.authMethods.includes('openid')
}
},
methods: {
async clickLoginWithOpenId() {
this.error = ''
const options = {
authorizationBaseUrl: `${this.serverConfig.address}/auth/openid`,
logsEnabled: true,
web: {
appId: 'com.audiobookshelf.web',
responseType: 'token',
redirectUrl: location.origin
},
android: {
appId: 'com.audiobookshelf.app',
responseType: 'code',
redirectUrl: 'com.audiobookshelf.app:/'
}
}
OAuth2Client.authenticate(options)
.then(async (response) => {
const token = response.authorization_response?.additional_parameters?.setToken || response.authorization_response?.setToken
if (token) {
this.serverConfig.token = token
const payload = await this.authenticateToken()
if (payload) {
this.setUserAndConnection(payload)
} else {
this.showAuth = true
}
} else {
this.error = 'Invalid response: No token'
}
})
.catch((error) => {
console.error('OAuth rejected', error)
this.error = error.toString?.() || error.message
})
},
addCustomHeaders() {
this.showAddCustomHeaders = true
},
@ -251,6 +297,23 @@ export default {
return response.data
}
},
/**
* Get request to server /status api endpoint
*
* @param {string} address
* @returns {Promise<{isInit:boolean, language:string, authMethods:string[]}>}
*/
getServerAddressStatus(address) {
return this.getRequest(`${address}/status`).catch((error) => {
console.error('Failed to get server status', error)
const errorMsg = error.message || error
this.error = 'Failed to ping server'
if (typeof errorMsg === 'string') {
this.error += ` (${errorMsg})`
}
return null
})
},
pingServerAddress(address, customHeaders) {
return this.getRequest(`${address}/ping`, customHeaders)
.then((data) => {
@ -302,10 +365,18 @@ export default {
this.serverConfig.address = validServerAddress
this.processing = true
this.error = null
this.authMethods = []
var success = await this.pingServerAddress(this.serverConfig.address, this.serverConfig.customHeaders)
const statusData = await this.getServerAddressStatus(this.serverConfig.address)
this.processing = false
if (success) this.showAuth = true
if (statusData) {
if (!statusData.isInit) {
this.error = 'Server is not initialized'
} else {
this.showAuth = true
this.authMethods = statusData.authMethods || []
}
}
},
async submitAuth() {
if (!this.networkConnected) return
@ -346,6 +417,7 @@ export default {
this.serverConfig.userId = user.id
this.serverConfig.token = user.token
this.serverConfig.username = user.username
var serverConnectionConfig = await this.$db.setServerConnectionConfig(this.serverConfig)

View file

@ -11,6 +11,7 @@ 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 'ByteowlsCapacitorOauth2', :path => '../../node_modules/@byteowls/capacitor-oauth2'
pod 'CapacitorApp', :path => '../../node_modules/@capacitor/app'
pod 'CapacitorClipboard', :path => '../../node_modules/@capacitor/clipboard'
pod 'CapacitorDialog', :path => '../../node_modules/@capacitor/dialog'

17
package-lock.json generated
View file

@ -6,8 +6,9 @@
"packages": {
"": {
"name": "audiobookshelf-app",
"version": "0.9.65-beta",
"version": "0.9.66-beta",
"dependencies": {
"@byteowls/capacitor-oauth2": "^5.0.0",
"@capacitor/android": "^5.0.0",
"@capacitor/app": "^5.0.0",
"@capacitor/clipboard": "^5.0.0",
@ -1938,6 +1939,14 @@
"node": ">=6.9.0"
}
},
"node_modules/@byteowls/capacitor-oauth2": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@byteowls/capacitor-oauth2/-/capacitor-oauth2-5.0.0.tgz",
"integrity": "sha512-yW50GypmyPJcH/95NwR2jJcgT78vBN3FYKL2w6A3vrT04bRLQyw2K0fLqfj8Zws6DJy43Ck1wPs0Bcdvbsub7A==",
"peerDependencies": {
"@capacitor/core": ">=5"
}
},
"node_modules/@capacitor/android": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz",
@ -21069,6 +21078,12 @@
"to-fast-properties": "^2.0.0"
}
},
"@byteowls/capacitor-oauth2": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@byteowls/capacitor-oauth2/-/capacitor-oauth2-5.0.0.tgz",
"integrity": "sha512-yW50GypmyPJcH/95NwR2jJcgT78vBN3FYKL2w6A3vrT04bRLQyw2K0fLqfj8Zws6DJy43Ck1wPs0Bcdvbsub7A==",
"requires": {}
},
"@capacitor/android": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@capacitor/android/-/android-5.4.0.tgz",

View file

@ -13,6 +13,7 @@
"ionic:serve": "npm run start"
},
"dependencies": {
"@byteowls/capacitor-oauth2": "^5.0.0",
"@capacitor/android": "^5.0.0",
"@capacitor/app": "^5.0.0",
"@capacitor/clipboard": "^5.0.0",

View file

@ -5,7 +5,7 @@
<script>
export default {
async asyncData({ params, app, store, redirect }) {
var series = await app.$axios.$get(`/api/series/${params.id}`).catch((error) => {
var series = await app.$nativeHttp.get(`/api/series/${params.id}`).catch((error) => {
console.error('Failed', error)
return false
})

View file

@ -38,7 +38,7 @@ export default {
return redirect(`/connect?redirect=${route.path}`)
}
var collection = await app.$axios.$get(`/api/collections/${params.id}`).catch((error) => {
var collection = await app.$nativeHttp.get(`/api/collections/${params.id}`).catch((error) => {
console.error('Failed', error)
return false
})

View file

@ -70,7 +70,7 @@ export default {
libraryItem = await app.$db.getLocalLibraryItem(libraryItemId)
console.log('Got lli', libraryItemId)
} else if (store.state.user.serverConnectionConfig) {
libraryItem = await app.$axios.$get(`/api/items/${libraryItemId}?expanded=1`).catch((error) => {
libraryItem = await app.$nativeHttp.get(`/api/items/${libraryItemId}?expanded=1`).catch((error) => {
console.error('Failed', error)
return false
})

View file

@ -150,7 +150,7 @@ export default {
libraryItem = await app.$db.getLocalLibraryItem(libraryItemId)
console.log('Got lli', libraryItemId)
} else if (store.state.user.serverConnectionConfig) {
libraryItem = await app.$axios.$get(`/api/items/${libraryItemId}?expanded=1&include=rssfeed`).catch((error) => {
libraryItem = await app.$nativeHttp.get(`/api/items/${libraryItemId}?expanded=1&include=rssfeed`).catch((error) => {
console.error('Failed', error)
return false
})

View file

@ -33,7 +33,7 @@ export default {
return redirect(`/connect?redirect=${route.path}`)
}
const playlist = await app.$axios.$get(`/api/playlists/${params.id}`).catch((error) => {
const playlist = await app.$nativeHttp.get(`/api/playlists/${params.id}`).catch((error) => {
console.error('Failed', error)
return false
})