mirror of
https://github.com/SkinnyMind/libgit2dart.git
synced 2025-05-05 04:39:07 -04:00
test(credentials): add more test cases
This commit is contained in:
parent
26812ffe9c
commit
4948bba773
4 changed files with 162 additions and 120 deletions
|
@ -1,34 +1,9 @@
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
import '../error.dart';
|
|
||||||
import '../util.dart';
|
import '../util.dart';
|
||||||
import 'libgit2_bindings.dart';
|
import 'libgit2_bindings.dart';
|
||||||
|
|
||||||
/// Create a credential to specify a username.
|
|
||||||
///
|
|
||||||
/// This is used with ssh authentication to query for the username if none is
|
|
||||||
/// specified in the url.
|
|
||||||
///
|
|
||||||
/// Throws a [LibGit2Error] if error occured.
|
|
||||||
Pointer<git_credential> username(String username) {
|
|
||||||
final out = calloc<Pointer<git_credential>>();
|
|
||||||
final usernameC = username.toNativeUtf8().cast<Int8>();
|
|
||||||
|
|
||||||
final error = libgit2.git_credential_username_new(out, usernameC);
|
|
||||||
|
|
||||||
calloc.free(usernameC);
|
|
||||||
|
|
||||||
if (error < 0) {
|
|
||||||
calloc.free(out);
|
|
||||||
throw LibGit2Error(libgit2.git_error_last());
|
|
||||||
} else {
|
|
||||||
return out.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new plain-text username and password credential object.
|
/// Create a new plain-text username and password credential object.
|
||||||
///
|
|
||||||
/// Throws a [LibGit2Error] if error occured.
|
|
||||||
Pointer<git_credential> userPass({
|
Pointer<git_credential> userPass({
|
||||||
required String username,
|
required String username,
|
||||||
required String password,
|
required String password,
|
||||||
|
@ -37,26 +12,15 @@ Pointer<git_credential> userPass({
|
||||||
final usernameC = username.toNativeUtf8().cast<Int8>();
|
final usernameC = username.toNativeUtf8().cast<Int8>();
|
||||||
final passwordC = password.toNativeUtf8().cast<Int8>();
|
final passwordC = password.toNativeUtf8().cast<Int8>();
|
||||||
|
|
||||||
final error = libgit2.git_credential_userpass_plaintext_new(
|
libgit2.git_credential_userpass_plaintext_new(out, usernameC, passwordC);
|
||||||
out,
|
|
||||||
usernameC,
|
|
||||||
passwordC,
|
|
||||||
);
|
|
||||||
|
|
||||||
calloc.free(usernameC);
|
calloc.free(usernameC);
|
||||||
calloc.free(passwordC);
|
calloc.free(passwordC);
|
||||||
|
|
||||||
if (error < 0) {
|
return out.value;
|
||||||
calloc.free(out);
|
|
||||||
throw LibGit2Error(libgit2.git_error_last());
|
|
||||||
} else {
|
|
||||||
return out.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new passphrase-protected ssh key credential object.
|
/// Create a new passphrase-protected ssh key credential object.
|
||||||
///
|
|
||||||
/// Throws a [LibGit2Error] if error occured.
|
|
||||||
Pointer<git_credential> sshKey({
|
Pointer<git_credential> sshKey({
|
||||||
required String username,
|
required String username,
|
||||||
required String publicKey,
|
required String publicKey,
|
||||||
|
@ -69,7 +33,7 @@ Pointer<git_credential> sshKey({
|
||||||
final privateKeyC = privateKey.toNativeUtf8().cast<Int8>();
|
final privateKeyC = privateKey.toNativeUtf8().cast<Int8>();
|
||||||
final passPhraseC = passPhrase.toNativeUtf8().cast<Int8>();
|
final passPhraseC = passPhrase.toNativeUtf8().cast<Int8>();
|
||||||
|
|
||||||
final error = libgit2.git_credential_ssh_key_new(
|
libgit2.git_credential_ssh_key_new(
|
||||||
out,
|
out,
|
||||||
usernameC,
|
usernameC,
|
||||||
publicKeyC,
|
publicKeyC,
|
||||||
|
@ -82,36 +46,22 @@ Pointer<git_credential> sshKey({
|
||||||
calloc.free(privateKeyC);
|
calloc.free(privateKeyC);
|
||||||
calloc.free(passPhraseC);
|
calloc.free(passPhraseC);
|
||||||
|
|
||||||
if (error < 0) {
|
return out.value;
|
||||||
calloc.free(out);
|
|
||||||
throw LibGit2Error(libgit2.git_error_last());
|
|
||||||
} else {
|
|
||||||
return out.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new ssh key credential object used for querying an ssh-agent.
|
/// Create a new ssh key credential object used for querying an ssh-agent.
|
||||||
///
|
|
||||||
/// Throws a [LibGit2Error] if error occured.
|
|
||||||
Pointer<git_credential> sshKeyFromAgent(String username) {
|
Pointer<git_credential> sshKeyFromAgent(String username) {
|
||||||
final out = calloc<Pointer<git_credential>>();
|
final out = calloc<Pointer<git_credential>>();
|
||||||
final usernameC = username.toNativeUtf8().cast<Int8>();
|
final usernameC = username.toNativeUtf8().cast<Int8>();
|
||||||
|
|
||||||
final error = libgit2.git_credential_ssh_key_from_agent(out, usernameC);
|
libgit2.git_credential_ssh_key_from_agent(out, usernameC);
|
||||||
|
|
||||||
calloc.free(usernameC);
|
calloc.free(usernameC);
|
||||||
|
|
||||||
if (error < 0) {
|
return out.value;
|
||||||
calloc.free(out);
|
|
||||||
throw LibGit2Error(libgit2.git_error_last());
|
|
||||||
} else {
|
|
||||||
return out.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new ssh key credential object reading the keys from memory.
|
/// Create a new ssh key credential object reading the keys from memory.
|
||||||
///
|
|
||||||
/// Throws a [LibGit2Error] if error occured.
|
|
||||||
Pointer<git_credential> sshKeyFromMemory({
|
Pointer<git_credential> sshKeyFromMemory({
|
||||||
required String username,
|
required String username,
|
||||||
required String publicKey,
|
required String publicKey,
|
||||||
|
@ -124,7 +74,7 @@ Pointer<git_credential> sshKeyFromMemory({
|
||||||
final privateKeyC = privateKey.toNativeUtf8().cast<Int8>();
|
final privateKeyC = privateKey.toNativeUtf8().cast<Int8>();
|
||||||
final passPhraseC = passPhrase.toNativeUtf8().cast<Int8>();
|
final passPhraseC = passPhrase.toNativeUtf8().cast<Int8>();
|
||||||
|
|
||||||
final error = libgit2.git_credential_ssh_key_memory_new(
|
libgit2.git_credential_ssh_key_memory_new(
|
||||||
out,
|
out,
|
||||||
usernameC,
|
usernameC,
|
||||||
publicKeyC,
|
publicKeyC,
|
||||||
|
@ -137,10 +87,5 @@ Pointer<git_credential> sshKeyFromMemory({
|
||||||
calloc.free(privateKeyC);
|
calloc.free(privateKeyC);
|
||||||
calloc.free(passPhraseC);
|
calloc.free(passPhraseC);
|
||||||
|
|
||||||
if (error < 0) {
|
return out.value;
|
||||||
calloc.free(out);
|
|
||||||
throw LibGit2Error(libgit2.git_error_last());
|
|
||||||
} else {
|
|
||||||
return out.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
import 'package:libgit2dart/libgit2dart.dart';
|
import 'package:libgit2dart/libgit2dart.dart';
|
||||||
|
import 'package:libgit2dart/src/util.dart';
|
||||||
import '../credentials.dart';
|
import '../credentials.dart';
|
||||||
import '../callbacks.dart';
|
import '../callbacks.dart';
|
||||||
import '../repository.dart';
|
import '../repository.dart';
|
||||||
|
@ -120,21 +121,34 @@ class RemoteCallbacks {
|
||||||
int allowedTypes,
|
int allowedTypes,
|
||||||
Pointer<Void> payload,
|
Pointer<Void> payload,
|
||||||
) {
|
) {
|
||||||
final credentialType = credentials!.credentialType;
|
if (payload.cast<Int8>().value == 2) {
|
||||||
if (allowedTypes & credentialType.value != credentialType.value) {
|
libgit2.git_error_set_str(
|
||||||
throw ArgumentError('Invalid credential type $credentialType');
|
git_error_t.GIT_ERROR_INVALID,
|
||||||
|
'Incorrect credentials.'.toNativeUtf8().cast<Int8>(),
|
||||||
|
);
|
||||||
|
throw LibGit2Error(libgit2.git_error_last());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (credentials is Username) {
|
final credentialType = credentials!.credentialType;
|
||||||
final cred = credentials as Username;
|
|
||||||
credPointer[0] = credentials_bindings.username(cred.username);
|
if (allowedTypes & credentialType.value != credentialType.value) {
|
||||||
} else if (credentials is UserPass) {
|
libgit2.git_error_set_str(
|
||||||
|
git_error_t.GIT_ERROR_INVALID,
|
||||||
|
'Invalid credential type $credentialType'.toNativeUtf8().cast<Int8>(),
|
||||||
|
);
|
||||||
|
throw LibGit2Error(libgit2.git_error_last());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credentials is UserPass) {
|
||||||
final cred = credentials as UserPass;
|
final cred = credentials as UserPass;
|
||||||
credPointer[0] = credentials_bindings.userPass(
|
credPointer[0] = credentials_bindings.userPass(
|
||||||
username: cred.username,
|
username: cred.username,
|
||||||
password: cred.password,
|
password: cred.password,
|
||||||
);
|
);
|
||||||
} else if (credentials is Keypair) {
|
payload.cast<Int8>().value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credentials is Keypair) {
|
||||||
final cred = credentials as Keypair;
|
final cred = credentials as Keypair;
|
||||||
credPointer[0] = credentials_bindings.sshKey(
|
credPointer[0] = credentials_bindings.sshKey(
|
||||||
username: cred.username,
|
username: cred.username,
|
||||||
|
@ -142,10 +156,16 @@ class RemoteCallbacks {
|
||||||
privateKey: cred.privateKey,
|
privateKey: cred.privateKey,
|
||||||
passPhrase: cred.passPhrase,
|
passPhrase: cred.passPhrase,
|
||||||
);
|
);
|
||||||
} else if (credentials is KeypairFromAgent) {
|
payload.cast<Int8>().value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credentials is KeypairFromAgent) {
|
||||||
final cred = credentials as KeypairFromAgent;
|
final cred = credentials as KeypairFromAgent;
|
||||||
credPointer[0] = credentials_bindings.sshKeyFromAgent(cred.username);
|
credPointer[0] = credentials_bindings.sshKeyFromAgent(cred.username);
|
||||||
} else if (credentials is KeypairFromMemory) {
|
payload.cast<Int8>().value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credentials is KeypairFromMemory) {
|
||||||
final cred = credentials as KeypairFromMemory;
|
final cred = credentials as KeypairFromMemory;
|
||||||
credPointer[0] = credentials_bindings.sshKeyFromMemory(
|
credPointer[0] = credentials_bindings.sshKeyFromMemory(
|
||||||
username: cred.username,
|
username: cred.username,
|
||||||
|
@ -153,6 +173,7 @@ class RemoteCallbacks {
|
||||||
privateKey: cred.privateKey,
|
privateKey: cred.privateKey,
|
||||||
passPhrase: cred.passPhrase,
|
passPhrase: cred.passPhrase,
|
||||||
);
|
);
|
||||||
|
payload.cast<Int8>().value++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -199,6 +220,8 @@ class RemoteCallbacks {
|
||||||
|
|
||||||
if (callbacks.credentials != null) {
|
if (callbacks.credentials != null) {
|
||||||
credentials = callbacks.credentials;
|
credentials = callbacks.credentials;
|
||||||
|
final payload = calloc<Int8>()..value = 1;
|
||||||
|
callbacksOptions.payload = payload.cast();
|
||||||
callbacksOptions.credentials = Pointer.fromFunction(
|
callbacksOptions.credentials = Pointer.fromFunction(
|
||||||
credentialsCb,
|
credentialsCb,
|
||||||
except,
|
except,
|
||||||
|
|
|
@ -5,20 +5,6 @@ abstract class Credentials {
|
||||||
GitCredential get credentialType;
|
GitCredential get credentialType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Credential with specific username.
|
|
||||||
class Username implements Credentials {
|
|
||||||
const Username(this.username);
|
|
||||||
|
|
||||||
/// The username to authenticate with.
|
|
||||||
final String username;
|
|
||||||
|
|
||||||
@override
|
|
||||||
GitCredential get credentialType => GitCredential.username;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => 'Username{username: $username}';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Plain-text username and password credential.
|
/// Plain-text username and password credential.
|
||||||
class UserPass implements Credentials {
|
class UserPass implements Credentials {
|
||||||
const UserPass({required this.username, required this.password});
|
const UserPass({required this.username, required this.password});
|
||||||
|
|
|
@ -17,15 +17,6 @@ void main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
group('Credentials', () {
|
group('Credentials', () {
|
||||||
test('successfully initializes username credentials', () {
|
|
||||||
final credentials = const Username('user');
|
|
||||||
|
|
||||||
expect(credentials, isA<Credentials>());
|
|
||||||
expect(credentials.username, 'user');
|
|
||||||
expect(credentials.credentialType, GitCredential.username);
|
|
||||||
expect(credentials.toString(), contains('Username{'));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('successfully initializes username/password credentials', () {
|
test('successfully initializes username/password credentials', () {
|
||||||
final credentials = const UserPass(
|
final credentials = const UserPass(
|
||||||
username: 'user',
|
username: 'user',
|
||||||
|
@ -82,18 +73,28 @@ void main() {
|
||||||
expect(credentials.toString(), contains('KeypairFromAgent{'));
|
expect(credentials.toString(), contains('KeypairFromAgent{'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sucessfully clones repository with provided username', () {
|
test('throws when provided username and password are incorrect', () {
|
||||||
final callbacks = const Callbacks(credentials: Username('git'));
|
final callbacks = const Callbacks(
|
||||||
|
credentials: UserPass(
|
||||||
final repo = Repository.clone(
|
username: 'libgit2',
|
||||||
url: 'https://git@github.com/libgit2/TestGitRepository',
|
password: 'libgit2',
|
||||||
localPath: cloneDir.path,
|
),
|
||||||
callbacks: callbacks,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(repo.isEmpty, false);
|
expect(
|
||||||
|
() => Repository.clone(
|
||||||
repo.free();
|
url: 'https://github.com/github/github',
|
||||||
|
localPath: cloneDir.path,
|
||||||
|
callbacks: callbacks,
|
||||||
|
),
|
||||||
|
throwsA(
|
||||||
|
isA<LibGit2Error>().having(
|
||||||
|
(e) => e.toString(),
|
||||||
|
'error',
|
||||||
|
"Incorrect credentials.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sucessfully clones repository with provided keypair', () {
|
test('sucessfully clones repository with provided keypair', () {
|
||||||
|
@ -122,7 +123,13 @@ void main() {
|
||||||
url: 'ssh://git@github.com/libgit2/TestGitRepository',
|
url: 'ssh://git@github.com/libgit2/TestGitRepository',
|
||||||
localPath: cloneDir.path,
|
localPath: cloneDir.path,
|
||||||
),
|
),
|
||||||
throwsA(isA<LibGit2Error>()),
|
throwsA(
|
||||||
|
isA<LibGit2Error>().having(
|
||||||
|
(e) => e.toString(),
|
||||||
|
'error',
|
||||||
|
"authentication required but no callback set",
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -141,7 +148,62 @@ void main() {
|
||||||
localPath: cloneDir.path,
|
localPath: cloneDir.path,
|
||||||
callbacks: callbacks,
|
callbacks: callbacks,
|
||||||
),
|
),
|
||||||
throwsA(isA<LibGit2Error>()),
|
throwsA(
|
||||||
|
isA<LibGit2Error>().having(
|
||||||
|
(e) => e.toString(),
|
||||||
|
'error',
|
||||||
|
"Failed to authenticate SSH session: Unable to open public key file",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('throws when provided keypair is incorrect', () {
|
||||||
|
final keypair = const Keypair(
|
||||||
|
username: 'git',
|
||||||
|
pubKey: 'test/assets/keys/id_rsa.pub',
|
||||||
|
privateKey: 'incorrect',
|
||||||
|
passPhrase: 'empty',
|
||||||
|
);
|
||||||
|
final callbacks = Callbacks(credentials: keypair);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
() => Repository.clone(
|
||||||
|
url: 'ssh://git@github.com/libgit2/TestGitRepository',
|
||||||
|
localPath: cloneDir.path,
|
||||||
|
callbacks: callbacks,
|
||||||
|
),
|
||||||
|
throwsA(
|
||||||
|
isA<LibGit2Error>().having(
|
||||||
|
(e) => e.toString(),
|
||||||
|
'error',
|
||||||
|
"Incorrect credentials.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('throws when provided credential type is invalid', () {
|
||||||
|
final callbacks = const Callbacks(
|
||||||
|
credentials: UserPass(
|
||||||
|
username: 'libgit2',
|
||||||
|
password: 'libgit2',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
() => Repository.clone(
|
||||||
|
url: 'ssh://git@github.com/libgit2/TestGitRepository',
|
||||||
|
localPath: cloneDir.path,
|
||||||
|
callbacks: callbacks,
|
||||||
|
),
|
||||||
|
throwsA(
|
||||||
|
isA<LibGit2Error>().having(
|
||||||
|
(e) => e.toString(),
|
||||||
|
'error',
|
||||||
|
"Invalid credential type GitCredential.userPassPlainText",
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,23 +229,49 @@ void main() {
|
||||||
repo.free();
|
repo.free();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sucessfully clones repository with provided username and password',
|
test('throws when provided keypair from memory is incorrect', () {
|
||||||
() {
|
final pubKey = File('test/assets/keys/id_rsa.pub').readAsStringSync();
|
||||||
final userPass = const UserPass(
|
final keypair = KeypairFromMemory(
|
||||||
username: 'libgit2',
|
username: 'git',
|
||||||
password: 'libgit2',
|
pubKey: pubKey,
|
||||||
|
privateKey: 'incorrect',
|
||||||
|
passPhrase: 'empty',
|
||||||
);
|
);
|
||||||
final callbacks = Callbacks(credentials: userPass);
|
final callbacks = Callbacks(credentials: keypair);
|
||||||
|
|
||||||
final repo = Repository.clone(
|
expect(
|
||||||
url: 'https://github.com/libgit2/TestGitRepository',
|
() => Repository.clone(
|
||||||
localPath: cloneDir.path,
|
url: 'ssh://git@github.com/libgit2/TestGitRepository',
|
||||||
callbacks: callbacks,
|
localPath: cloneDir.path,
|
||||||
|
callbacks: callbacks,
|
||||||
|
),
|
||||||
|
throwsA(
|
||||||
|
isA<LibGit2Error>().having(
|
||||||
|
(e) => e.toString(),
|
||||||
|
'error',
|
||||||
|
"Incorrect credentials.",
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
expect(repo.isEmpty, false);
|
test('throws when provided keypair from agent is incorrect', () {
|
||||||
|
final callbacks = const Callbacks(credentials: KeypairFromAgent('git'));
|
||||||
|
|
||||||
repo.free();
|
expect(
|
||||||
|
() => Repository.clone(
|
||||||
|
url: 'ssh://git@github.com/libgit2/TestGitRepository',
|
||||||
|
localPath: cloneDir.path,
|
||||||
|
callbacks: callbacks,
|
||||||
|
),
|
||||||
|
throwsA(
|
||||||
|
isA<LibGit2Error>().having(
|
||||||
|
(e) => e.toString(),
|
||||||
|
'error',
|
||||||
|
"Incorrect credentials.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue