Upload main.js via GUI

This commit is contained in:
2025-12-28 20:45:06 +00:00
parent 394bb26891
commit d2e977f687

103
main.js
View File

@@ -19,8 +19,19 @@ const {
const { initRepo, commitAndPush, getBranches, getCommitLogs } = require('./src/git/gitHandler.js');
const DATA_DIR = ppath.join(__dirname, 'data');
const CREDENTIALS_FILE = ppath.join(DATA_DIR, 'credentials.json');
// NOTE: credentials/data location is computed via getDataDir() to avoid calling app.getPath before ready
function getDataDir() {
try {
return ppath.join(app.getPath('userData'), 'data');
} catch (e) {
// Fallback: use __dirname/data (only if app.getPath not available)
return ppath.join(__dirname, 'data');
}
}
function getCredentialsFilePath() {
return ppath.join(getDataDir(), 'credentials.json');
}
const ALGORITHM = 'aes-256-cbc';
const SECRET_KEY = crypto.scryptSync('SuperSecretKey123!', 'salt', 32);
const IV = Buffer.alloc(16, 0);
@@ -30,6 +41,50 @@ const DEFAULT_CONCURRENCY = 4;
// temp drag cleanup delay (ms)
const TMP_CLEANUP_MS = 20_000;
/* -----------------------------
Utilities for safe filesystem ops
----------------------------- */
function ensureDir(dirPath) {
try {
if (fs.existsSync(dirPath)) {
if (!fs.statSync(dirPath).isDirectory()) {
// If a file exists where we expect a directory, remove it
fs.unlinkSync(dirPath);
}
}
fs.mkdirSync(dirPath, { recursive: true });
} catch (e) {
// Re-throw with clearer message
throw new Error(`ensureDir failed for ${dirPath}: ${e && e.message ? e.message : e}`);
}
}
/**
* Create a safe, unique temporary directory under os.tmpdir().
* If an entry exists at that path and it's a file, it will be removed.
* If a directory exists it will be removed and recreated to ensure a clean state.
* Returns the created directory path.
*
* baseName should be a short string (no path separators). We append a timestamp to reduce collisions.
*/
function getSafeTmpDir(baseName) {
const safeBase = (baseName || 'tmp').replace(/[<>:"/\\|?*\x00-\x1F]/g, '_').substring(0, 64);
const dir = ppath.join(os.tmpdir(), `${safeBase}-${Date.now()}`);
try {
if (fs.existsSync(dir)) {
if (!fs.statSync(dir).isDirectory()) fs.unlinkSync(dir);
else fs.rmSync(dir, { recursive: true, force: true });
}
fs.mkdirSync(dir, { recursive: true });
return dir;
} catch (e) {
throw new Error(`getSafeTmpDir failed for ${dir}: ${e && e.message ? e.message : e}`);
}
}
/* -----------------------------
app / window
----------------------------- */
function createWindow() {
// Entfernt das Menü (File, Edit, View...) komplett
Menu.setApplicationMenu(null);
@@ -58,6 +113,7 @@ app.on('window-all-closed', () => { if (process.platform !== 'darwin') app.quit(
----------------------------- */
function readCredentials() {
try {
const CREDENTIALS_FILE = getCredentialsFilePath();
if (!fs.existsSync(CREDENTIALS_FILE)) return null;
const encrypted = fs.readFileSync(CREDENTIALS_FILE);
const decipher = crypto.createDecipheriv(ALGORITHM, SECRET_KEY, IV);
@@ -117,7 +173,9 @@ ipcMain.handle('select-file', async () => {
ipcMain.handle('save-credentials', async (event, data) => {
try {
fs.mkdirSync(DATA_DIR, { recursive: true });
const DATA_DIR = getDataDir();
const CREDENTIALS_FILE = getCredentialsFilePath();
ensureDir(DATA_DIR); // robust gegen ENOTDIR
const json = JSON.stringify(data);
const cipher = crypto.createCipheriv(ALGORITHM, SECRET_KEY, IV);
const encrypted = Buffer.concat([cipher.update(json, 'utf8'), cipher.final()]);
@@ -138,6 +196,9 @@ ipcMain.handle('load-credentials', async () => {
}
});
/* -----------------------------
Repo & git handlers
----------------------------- */
ipcMain.handle('create-repo', async (event, data) => {
try {
const credentials = readCredentials();
@@ -358,9 +419,11 @@ ipcMain.handle('get-gitea-repo-contents', async (event, data) => {
const owner = data.owner;
const repo = data.repo;
const p = data.path || '';
// FIXED: Konvertiere 'master' zu 'main'
let ref = data.ref || 'main';
if (ref === 'master') ref = 'main';
// FIXED: Pass data.ref directly to apiHandler without forcing 'main'
// This allows apiHandler.js to try ['main', 'master'] if no ref is passed
const ref = data.ref;
const items = await getGiteaRepoContents({ token, url, owner, repo, path: p, ref });
return { ok: true, items };
} catch (e) {
@@ -378,9 +441,10 @@ ipcMain.handle('get-gitea-file-content', async (event, data) => {
const owner = data.owner;
const repo = data.repo;
const p = data.path;
// FIXED: Konvertiere 'master' zu 'main'
let ref = data.ref || 'main';
if (ref === 'master') ref = 'main';
// FIXED: Pass data.ref directly
const ref = data.ref;
const content = await getGiteaFileContent({ token, url, owner, repo, path: p, ref });
return { ok: true, content };
} catch (e) {
@@ -399,7 +463,7 @@ ipcMain.handle('upload-gitea-file', async (event, data) => {
const repo = data.repo;
// destPath is the target folder in the repo
const destPath = (data.destPath || '').replace(/^\//, '').replace(/\/$/, '');
// FIXED: Konvertiere 'master' zu 'main'
// FIXED: Konvertiere 'master' zu 'main' (Upload should generally target main)
let branch = data.branch || 'main';
if (branch === 'master') branch = 'main';
const message = data.message || 'Upload via Git Manager GUI';
@@ -607,11 +671,8 @@ ipcMain.handle('prepare-download-drag', async (event, data) => {
const repo = data.repo;
const remotePath = (data.path || '').replace(/^\/+/, '').replace(/\/+$/, '');
const tmpBase = ppath.join(os.tmpdir(), repo);
if (fs.existsSync(tmpBase)) {
try { fs.rmSync(tmpBase, { recursive: true, force: true }); } catch (e) { console.warn('Cleanup failed', e); }
}
fs.mkdirSync(tmpBase, { recursive: true });
// Use safe tmp dir (unique)
const tmpBase = getSafeTmpDir(repo || 'gitea-repo');
const allFiles = [];
async function gather(pathInRepo) {
@@ -768,9 +829,7 @@ ipcMain.handle('upload-and-push', async (event, data) => {
}
} catch (err) {}
const tmpDir = ppath.join(os.tmpdir(), `git-push-file-${owner}-${repo}-${Date.now()}`);
fs.mkdirSync(tmpDir, { recursive: true });
const tmpDir = getSafeTmpDir(`git-push-file-${owner}-${repo}`);
try {
execSync(`git clone --depth 1 --branch ${branch} "${authClone}" "${tmpDir}"`, { stdio: 'inherit' });
@@ -778,7 +837,7 @@ ipcMain.handle('upload-and-push', async (event, data) => {
let destDirInRepo = tmpDir;
if (destPath) {
destDirInRepo = ppath.join(tmpDir, destPath.split('/').join(ppath.sep));
fs.mkdirSync(destDirInRepo, { recursive: true });
ensureDir(destDirInRepo);
}
const finalFileDest = ppath.join(destDirInRepo, fileName);
@@ -796,7 +855,6 @@ ipcMain.handle('upload-and-push', async (event, data) => {
} catch (gitErr) {
console.error('Git Fallback failed:', gitErr);
if (fs.existsSync(tmpDir)) fs.rmSync(tmpDir, { recursive: true, force: true });
// Wir werfen den ursprünglichen Fehler, da der Fallback auch gescheitert ist
return { ok: false, error: `API failed: ${e.message}. Git fallback failed: ${String(gitErr)}` };
}
}
@@ -829,8 +887,7 @@ ipcMain.handle('upload-and-push', async (event, data) => {
}
} catch (e) {}
const tmpDir = ppath.join(os.tmpdir(), `gitea-push-${owner}-${repo}-${Date.now()}`);
fs.mkdirSync(tmpDir, { recursive: true });
const tmpDir = getSafeTmpDir(`gitea-push-${owner}-${repo}`);
try {
execSync(`git clone --depth 1 --branch ${branch} "${authClone}" "${tmpDir}"`, { stdio: 'inherit' });
@@ -843,7 +900,7 @@ ipcMain.handle('upload-and-push', async (event, data) => {
// Wenn ein Zielpfad angegeben ist (z.B. 'src'), erstelle diesen Ordner im Repo
const osDestPath = destPath.split('/').join(ppath.sep);
targetBaseDir = ppath.join(tmpDir, osDestPath);
fs.mkdirSync(targetBaseDir, { recursive: true });
ensureDir(targetBaseDir);
}
// Ziel ist immer: targetBaseDir/folderName