Upload main.js via GUI
This commit is contained in:
103
main.js
103
main.js
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user