-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Expose promptForPassword function #881
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,14 @@ | |
* SPDX-License-Identifier: MIT | ||
*/ | ||
import Vue from 'vue' | ||
import type { ComponentInstance } from 'vue' | ||
|
||
import { Axios } from '@nextcloud/axios' | ||
import { getCurrentUser } from '@nextcloud/auth' | ||
|
||
import PasswordDialogVue from './components/PasswordDialog.vue' | ||
import { DIALOG_ID, MODAL_CLASS } from './globals' | ||
|
||
import type { ComponentInstance } from 'vue' | ||
|
||
const PAGE_LOAD_TIME = Date.now() | ||
|
||
/** | ||
|
@@ -34,15 +37,25 @@ | |
* or confirmation is already in process. | ||
*/ | ||
export const confirmPassword = (): Promise<void> => { | ||
if (!isPasswordConfirmationRequired()) { | ||
return Promise.resolve() | ||
} | ||
|
||
return getPasswordDialog() | ||
} | ||
|
||
/** | ||
* | ||
* @param mode | ||
Check warning on line 49 in src/main.ts GitHub Actions / NPM lint
Check warning on line 49 in src/main.ts GitHub Actions / NPM lint
|
||
* @param callback | ||
Check warning on line 50 in src/main.ts GitHub Actions / NPM lint
|
||
* @return | ||
*/ | ||
function getPasswordDialog(callback?: (password: string) => Promise<any>): Promise<void> { | ||
const isDialogMounted = Boolean(document.getElementById(DIALOG_ID)) | ||
if (isDialogMounted) { | ||
return Promise.reject(new Error('Password confirmation dialog already mounted')) | ||
} | ||
|
||
if (!isPasswordConfirmationRequired()) { | ||
return Promise.resolve() | ||
} | ||
|
||
const mountPoint = document.createElement('div') | ||
mountPoint.setAttribute('id', DIALOG_ID) | ||
|
||
|
@@ -61,7 +74,7 @@ | |
|
||
const DialogClass = Vue.extend(PasswordDialogVue) | ||
// Mount point element is replaced by the component | ||
const dialog = (new DialogClass() as ComponentInstance).$mount(mountPoint) | ||
const dialog = (new DialogClass({ propsData: { callback } }) as ComponentInstance).$mount(mountPoint) | ||
|
||
return new Promise((resolve, reject) => { | ||
dialog.$on('confirmed', () => { | ||
|
@@ -74,3 +87,43 @@ | |
}) | ||
}) | ||
} | ||
|
||
/** | ||
* Add interceptors to an axios instance that for every request | ||
* will prompt for password confirmation and add it as Basic Auth. | ||
* @param axios | ||
Check warning on line 94 in src/main.ts GitHub Actions / NPM lint
|
||
*/ | ||
export function withPasswordConfirmation(axios: Axios): Axios { | ||
const { | ||
promise: passwordDialogCallbackResolution, | ||
resolve: resolvePwdDialogCallback, | ||
reject: rejectPwdDialogCallback, | ||
} = Promise.withResolvers() | ||
|
||
axios.interceptors.request.use(async (config) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should get the interceptor ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking of creating a new axios instance instead. So this instance would always ask for pwd confirmation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or if we want it to be a one time thing, then something like that might make more sense: axios.post({
passwordConfirmation: true,
// ...
} And then add the interceptor in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think this is too complex for using, if I have an API to query and only one endpoint is protected, then why do I need two axios instances? It gets even worse if I need to configure both the same way and just need the password confirmation.
I think one time thing makes more sense, so the two proposed ways are:
But either way I would not move this to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also like your idea with the plugin, but I am not sure how we could do this in a clean way. Also for example the password confirmation is only needed if the request is done using a user session, but it is not required if you do the requests in no-ui mode using app tokens for authentication (valid use case, but the only real using app I know for something like this currently would be the Talk desktop app). While writing this: So what do you think of moving this function to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, would make sense to have it all in axios then. Let me draft a PR. |
||
return new Promise((resolve, reject) => { | ||
getPasswordDialog((password: string) => { | ||
resolve({ | ||
...config, | ||
auth: { | ||
username: getCurrentUser()?.uid ?? '', | ||
password, | ||
}, | ||
}) | ||
|
||
// Await for request to be done | ||
return passwordDialogCallbackResolution | ||
}) | ||
}) | ||
}) | ||
|
||
axios.interceptors.response.use((response) => { | ||
if (response.request.auth !== undefined) { | ||
resolvePwdDialogCallback(undefined) | ||
} | ||
|
||
return response | ||
}) | ||
|
||
return axios | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requires a default like
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it has a default, then it won't be undefined later on and the old behavior will never be called. I think that I tried to set
undefined
as default, but it failed.