Skip to content
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

Frontend Cache Credentials for Issue #659 #1091

Closed
wants to merge 11 commits into from
24 changes: 18 additions & 6 deletions src/commandsAndMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1367,26 +1367,35 @@ export async function showGitOperationDialog<T>(
operation: Operation,
trans: TranslationBundle,
args?: T,
authentication?: Git.IAuth,
retry = false
authentication?: Git.IAuthWithCacheCredentials,
retry = false,
cache = false
): Promise<string> {
try {
const auth = authentication ? {
username: authentication.username,
password: authentication.password
} as Git.IAuth : undefined;
let result: Git.IResultWithMessage;
// the Git action
switch (operation) {
case Operation.Clone:
// eslint-disable-next-line no-case-declarations
const { path, url } = args as any as IGitCloneArgs;
result = await model.clone(path, url, authentication);
result = await model.clone(path,
url,
auth,
authentication ? authentication.cacheCredentials : false
);
break;
case Operation.Pull:
result = await model.pull(authentication);
break;
case Operation.Push:
result = await model.push(authentication);
result = await model.push(authentication, false, authentication.cacheCredentials);
break;
case Operation.ForcePush:
result = await model.push(authentication, true);
result = await model.push(authentication, true, authentication.cacheCredentials);
break;
default:
result = { code: -1, message: 'Unknown git command' };
Expand All @@ -1407,7 +1416,10 @@ export async function showGitOperationDialog<T>(
trans,
trans.__('Enter credentials for remote repository'),
retry ? trans.__('Incorrect username or password.') : ''
)
)//,
//buttons: [
// Dialog.cacheCredentials({label: trans.__('Cache Credentials?')})
//]
});

if (credentials.button.accept) {
Expand Down
30 changes: 24 additions & 6 deletions src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,8 @@ export class GitExtension implements IGitExtension {
async clone(
path: string,
url: string,
auth?: Git.IAuth
auth?: Git.IAuth,
cacheCredentials = false
): Promise<Git.IResultWithMessage> {
return await this._taskHandler.execute<Git.IResultWithMessage>(
'git:clone',
Expand All @@ -587,7 +588,8 @@ export class GitExtension implements IGitExtension {
'POST',
{
clone_url: url,
auth: auth as any
auth: auth as any,
cache_credentials: cacheCredentials
}
);
}
Expand Down Expand Up @@ -822,7 +824,7 @@ export class GitExtension implements IGitExtension {
* @throws {Git.GitResponseError} If the server response is not ok
* @throws {ServerConnection.NetworkError} If the request cannot be made
*/
async pull(auth?: Git.IAuth): Promise<Git.IResultWithMessage> {
async pull(auth?: Git.IAuth, cache_credentials: true): Promise<Git.IResultWithMessage> {
const path = await this._getPathRepository();
const data = this._taskHandler.execute<Git.IResultWithMessage>(
'git:pull',
Expand Down Expand Up @@ -855,7 +857,7 @@ export class GitExtension implements IGitExtension {
* @throws {Git.GitResponseError} If the server response is not ok
* @throws {ServerConnection.NetworkError} If the request cannot be made
*/
async push(auth?: Git.IAuth, force = false): Promise<Git.IResultWithMessage> {
async push(auth?: Git.IAuth, cache_credentials: true, force = false, cacheCredentials = false): Promise<Git.IResultWithMessage> {
const path = await this._getPathRepository();
const data = this._taskHandler.execute<Git.IResultWithMessage>(
'git:push',
Expand All @@ -865,7 +867,8 @@ export class GitExtension implements IGitExtension {
'POST',
{
auth: auth as any,
force: force
force: force,
cache_credentials: cacheCredentials
}
);
}
Expand Down Expand Up @@ -1494,7 +1497,22 @@ export class GitExtension implements IGitExtension {
private _fetchRemotes = async (): Promise<void> => {
try {
const path = await this._getPathRepository();
await requestAPI(URLExt.join(path, 'remote', 'fetch'), 'POST');

const credentials = await showDialog({
title: trans.__('Git credentials required'),
body: new GitCredentialsForm(
trans,
trans.__('Enter credentials for remote repository'),
retry ? trans.__('Incorrect username or password.') : ''
)//,
//buttons: [
// Dialog.cacheCredentials({label: trans.__('Cache Credentials?')})
//]
});

await requestAPI(URLExt.join(path, 'remote', 'fetch'), 'POST', {
auth?: Git.IAuth, cache_credentials: true
});
} catch (error) {
console.error('Failed to fetch remotes', error);
}
Expand Down
7 changes: 7 additions & 0 deletions src/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,13 @@ export namespace Git {
password: string;
}

/**
* Interface for the Git Auth request with credentials caching option
*/
export interface IAuthWithCacheCredentials extends IAuth {
cacheCredentials: boolean;
}

/**
* Structure for the request to the Git Clone API.
*/
Expand Down
19 changes: 17 additions & 2 deletions src/widgets/CredentialsBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@ export class GitCredentialsForm
private createBody(textContent: string, warningContent: string): HTMLElement {
const node = document.createElement('div');
const label = document.createElement('label');
const checkBoxLabel = document.createElement('label');
this._checkboxCacheCredentials = document.createElement('input');
this._user = document.createElement('input');
this._password = document.createElement('input');
//this._cacheCredentials = document.createElement('input');
this._password.type = 'password';


const text = document.createElement('span');
const warning = document.createElement('div');

Expand All @@ -35,13 +39,20 @@ export class GitCredentialsForm
text.textContent = textContent;
warning.textContent = warningContent;
this._user.placeholder = this._trans.__('username');
this._checkboxCacheCredentials.type = 'checkbox';
this._checkboxCacheCredentials.textContent = this._trans.__("Save my login temporarily");
//this._cacheCredentials.placeholder = this._trans.__('Cache credentials?');
this._password.placeholder = this._trans.__(
'password / personal access token'

);

label.appendChild(text);
label.appendChild(this._user);
label.appendChild(this._password);
checkBoxLabel.appendChild(this._checkboxCacheCredentials);
node.appendChild(checkBoxLabel);
//label.appendChild(this._cacheCredentials);
node.appendChild(label);
node.appendChild(warning);
return node;
Expand All @@ -50,13 +61,17 @@ export class GitCredentialsForm
/**
* Returns the input value.
*/
getValue(): Git.IAuth {
getValue(): Git.IAuthWithCacheCredentials {
return {
username: this._user.value,
password: this._password.value
password: this._password.value,
cacheCredentials: this._checkboxCacheCredentials.checked
};
Comment on lines +64 to 69
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would extend Git.IAuth with a new optional parameter cacheCredentials. This will allow you to simply pass-by those information through the model and then to the server. One reason for that is the strong bound between that parameter and the credentials; passing it as a separate argument as done currently would be interesting if it had an effect even if the authentication was not defined.

// return this._cacheCredentials;
}
protected _trans: TranslationBundle;
private _user: HTMLInputElement;
private _password: HTMLInputElement;
private _checkboxCacheCredentials: HTMLInputElement;
//private _cacheCredentials: HTMLInputElement;
}