Merge pull request #513 from exactly-one-kas/fix-windows-credentials

Fix windows credentials
This commit is contained in:
Murmele 2023-04-16 10:55:16 +02:00 committed by GitHub
commit 1e5e00a1f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 50 additions and 173 deletions

View File

@ -15,7 +15,7 @@ set(GITTYUP_VERSION
string(TIMESTAMP CURR_YEAR "%Y")
add_compile_definitions(CURR_YEAR=${CURR_YEAR})
configure_file(${CMAKE_SOURCE_DIR}/LICENSE.md.in ${CMAKE_SOURCE_DIR}/LICENSE.md
@ONLY)
@ONLY NEWLINE_STYLE UNIX)
# Write version to file so it can be used also from external, for example in the
# github manifest

View File

@ -4,8 +4,9 @@ if(NOT USE_SYSTEM_GIT)
macro(add_helper NAME)
set(TARGET git-credential-${NAME})
add_executable(${TARGET} ${PATH}/${NAME}/${TARGET}.c)
set_target_properties(${TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
$<TARGET_FILE_DIR:gittyup>)
set_target_properties(
${TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
$<TARGET_FILE_DIR:gittyup>/credential-helpers)
if(${ARGC} GREATER 1)
target_link_libraries(${TARGET} ${ARGV1})
@ -14,7 +15,7 @@ if(NOT USE_SYSTEM_GIT)
if(NOT APPLE)
install(
TARGETS ${TARGET}
DESTINATION ${CMAKE_INSTALL_BINDIR}
DESTINATION ${CMAKE_INSTALL_BINDIR}/credential-helpers
COMPONENT ${GITTYUP_NAME})
endif()
endmacro()

View File

@ -1,9 +1,4 @@
if(WIN32)
set(CREDENTIAL_IMPL_FILE WinCred.cpp)
endif()
add_library(cred Cache.cpp Store.cpp CredentialHelper.cpp GitCredential.cpp
${CREDENTIAL_IMPL_FILE})
add_library(cred Cache.cpp Store.cpp CredentialHelper.cpp GitCredential.cpp)
target_link_libraries(cred conf git Qt5::Core)

View File

@ -10,7 +10,6 @@
#include "CredentialHelper.h"
#include "Cache.h"
#include "GitCredential.h"
#include "WinCred.h"
#include "Store.h"
#include "conf/Settings.h"
#include "git/Config.h"
@ -45,13 +44,7 @@ CredentialHelper *CredentialHelper::instance() {
auto path =
QString::fromLocal8Bit(qgetenv("HOME") + "/.git-credentials");
instance = new Store(path);
}
#if defined(Q_OS_WIN)
else if (helperName == winCredStoreName) {
instance = new WinCred;
}
#endif
else {
} else {
instance = new GitCredential(helperName);
}
}

View File

@ -8,6 +8,7 @@
//
#include "GitCredential.h"
#include <QStandardPaths>
#include <QCoreApplication>
#include <QDir>
#include <QProcess>
@ -92,6 +93,46 @@ bool GitCredential::store(const QString &url, const QString &username,
}
QString GitCredential::command() const {
QDir dir(QCoreApplication::applicationDirPath());
return dir.filePath(QString("git-credential-%1").arg(mName));
QString name = QString("git-credential-%1").arg(mName);
QDir appDir = QCoreApplication::applicationDirPath();
appDir.cd("credential-helpers");
// Prefer credential helpers directly installed into Gittyup's app dir
QString candidate =
QStandardPaths::findExecutable(name, QStringList(appDir.path()));
if (!candidate.isEmpty()) {
return candidate;
}
candidate = QStandardPaths::findExecutable(name);
if (!candidate.isEmpty()) {
return candidate;
}
#ifdef Q_OS_WIN
// Look for GIT CLI installation path
QString gitPath = QStandardPaths::findExecutable("git");
if (!gitPath.isEmpty()) {
QDir gitDir = QFileInfo(gitPath).dir();
if (gitDir.dirName() == "cmd" || gitDir.dirName() == "bin") {
gitDir.cdUp();
#ifdef Q_OS_WIN64
gitDir.cd("mingw64");
#else
gitDir.cd("mingw32");
#endif
gitDir.cd("bin");
candidate =
QStandardPaths::findExecutable(name, QStringList(gitDir.path()));
if (!candidate.isEmpty()) {
return candidate;
}
}
}
#endif
return name;
}

View File

@ -1,128 +0,0 @@
//
// Copyright (c) 2018, Scientific Toolworks, Inc.
//
// This software is licensed under the MIT License. The LICENSE.md file
// describes the conditions under which this software may be distributed.
//
// Author: Jason Haslam
//
#include "WinCred.h"
#include <QStringList>
#include <QUrl>
#include <windows.h>
#include <wincred.h>
// Attempt to be compatible with the git wincred helper by matching
// the target name and encoding the password in UTF-16.
namespace {
const QString kNameFmt = "%1@%2";
const QString kTargetFmt = "git:https://%1";
QString buildTarget(const QString &host, const QString &name) {
return kTargetFmt.arg(name.isEmpty() ? host : kNameFmt.arg(name, host));
}
QString host(const QString &url) {
QString host = QUrl(url).host();
if (!host.isEmpty())
return host;
// Extract hostname from SSH URL.
int end = url.indexOf(':');
int begin = url.indexOf('@') + 1;
return url.mid(begin, end - begin);
}
} // namespace
WinCred::WinCred() {}
bool WinCred::get(const QString &url, QString &username, QString &password) {
log(QString("get: %1 %2").arg(url, username));
PCREDENTIAL cred;
QString target = buildTarget(host(url), username);
if (!CredRead(target.toUtf8(), CRED_TYPE_GENERIC, 0, &cred)) {
switch (DWORD error = GetLastError()) {
case ERROR_NOT_FOUND:
log(QString("get: credential not found for '%1'").arg(target));
break;
case ERROR_NO_SUCH_LOGON_SESSION:
log("get: no such logon session");
break;
case ERROR_INVALID_FLAGS:
log("get: invalid flags");
break;
default:
log(QString("get: unknown error '%1'").arg(error));
break;
}
return false;
}
username = cred->UserName;
int size = cred->CredentialBlobSize / sizeof(ushort);
password = QString::fromUtf16((ushort *)cred->CredentialBlob, size);
CredFree(cred);
return true;
}
bool WinCred::store(const QString &url, const QString &username,
const QString &password) {
log(QString("store: %1 %2").arg(url, username));
bool result = false;
QByteArray name = username.toUtf8();
QStringList names = {QString(), username};
foreach (const QString &tmp, names) {
QByteArray target = buildTarget(host(url), tmp).toUtf8();
CREDENTIAL cred;
cred.Flags = 0;
cred.Type = CRED_TYPE_GENERIC;
cred.TargetName = target.data();
cred.Comment = "Written by GitAhead";
cred.CredentialBlobSize = password.length() * sizeof(ushort);
cred.CredentialBlob = (LPBYTE)password.utf16();
cred.Persist = CRED_PERSIST_LOCAL_MACHINE;
cred.AttributeCount = 0;
cred.Attributes = nullptr;
cred.TargetAlias = nullptr;
cred.UserName = name.data();
if (CredWrite(&cred, 0)) {
result = true;
} else {
switch (DWORD error = GetLastError()) {
case ERROR_NO_SUCH_LOGON_SESSION:
log("store: no such logon session");
break;
case ERROR_INVALID_PARAMETER:
log("store: invalid parameter");
case ERROR_INVALID_FLAGS:
log("store: invalid flags");
break;
case ERROR_BAD_USERNAME:
log(QString("store: bad username '%1'").arg(username));
break;
default:
log(QString("store: unknown error '%1'").arg(error));
break;
}
}
}
return result;
}

View File

@ -1,25 +0,0 @@
//
// Copyright (c) 2018, Scientific Toolworks, Inc.
//
// This software is licensed under the MIT License. The LICENSE.md file
// describes the conditions under which this software may be distributed.
//
// Author: Jason Haslam
//
#ifndef WINCRED_H
#define WINCRED_H
#include "CredentialHelper.h"
class WinCred : public CredentialHelper {
public:
WinCred();
bool get(const QString &url, QString &username, QString &password) override;
bool store(const QString &url, const QString &username,
const QString &password) override;
};
#endif