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

Fix: Add custom About dialog for non-macOS platforms (#421) #1175

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 103 additions & 24 deletions td.vue/src/desktop/menu.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import { app, dialog } from 'electron';
import { app, dialog, BrowserWindow } from 'electron';
import path from 'path';
import logger from './logger.js';
import { isMacOS } from './utils.js';
Expand Down Expand Up @@ -30,7 +30,7 @@ import zho from '@/i18n/zh.js';

const messages = { ara, deu, ell, eng, fin, fra, hin, id, jpn, ms, por, spa, zho };
// hide RUS & UKR for now: const messages = { ara, deu, ell, eng, fin, fra, hin, id, jpn, ms, por, rus, spa, ukr, zho };
const languages = [ 'ara', 'deu', 'ell', 'eng', 'fin', 'fra', 'hin', 'id', 'jpn', 'ms', 'por', 'spa', 'zho' ];
const languages = ['ara', 'deu', 'ell', 'eng', 'fin', 'fra', 'hin', 'id', 'jpn', 'ms', 'por', 'spa', 'zho'];
// hide RUS & UKR for now: const languages = [ 'ara', 'deu', 'ell', 'eng', 'fin', 'fra', 'hin', 'id', 'jpn', 'ms', 'por', 'rus', 'spa', 'ukr', 'zho' ];
const defaultLanguage = 'eng';
var language = defaultLanguage;
Expand All @@ -41,33 +41,33 @@ export const model = {
isOpen: false
};

export function getMenuTemplate () {
export function getMenuTemplate() {
var menuTemplate = (isMacOS ? [{ role: 'appMenu' }] : []);
menuTemplate.push(
{
label: messages[language].desktop.file.heading,
submenu: [
{
label: messages[language].desktop.file.open,
click () {
click() {
openModelRequest('');
}
},
{
label: messages[language].desktop.file.save,
click () {
click() {
saveModel();
}
},
{
label: messages[language].desktop.file.saveAs,
click () {
click() {
saveModelAs();
}
},
{
label: messages[language].desktop.file.new,
click () {
click() {
newModel();
}
},
Expand All @@ -76,13 +76,13 @@ export function getMenuTemplate () {
submenu: [
{
label: messages[language].forms.exportHtml,
click () {
click() {
printModel('HTML');
}
},
{
label: messages[language].forms.exportPdf,
click () {
click() {
printModel('PDF');
}
},
Expand All @@ -98,7 +98,7 @@ export function getMenuTemplate () {
},
{
label: messages[language].desktop.file.close,
click () {
click() {
closeModelRequest();
}
},
Expand Down Expand Up @@ -153,7 +153,86 @@ export function getMenuTemplate () {
}
},
{ type: 'separator' },
{ role: 'about' }
{
label: 'About', // "About Electron" label
click: () => {
if (process.platform !== 'darwin') { // Check for non-macOS systems
const aboutWin = new BrowserWindow({
width: 800,
height: 700,
modal: true,
parent: mainWindow, // Use mainWindow as the parent if applicable
resizable: false,
webPreferences: {
nodeIntegration: true, // Optional, if you need node integration
}
});

// Set the content directly within the BrowserWindow
const aboutContent = `
<html>
<head>
<title>About Threat Dragon</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
background-color: #f4f4f9;
color: #333;
}
h1 {
color: #2d3a4f;
}
p {
color: #666;
line-height: 1.6;
}
a {
color: #007bff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<h1>About Threat Dragon</h1>
<p>Threat Dragon is an open-source threat modeling tool developed by OWASP (Open Web Application Security Project). It allows you to design and analyze your application’s security by identifying potential threats and vulnerabilities.</p>
<p>It is available as a desktop application that works across multiple platforms, helping you create threat models that can be shared and collaborated upon. This tool is designed for developers and security professionals to visualize their system architecture and the threats that could potentially affect it.</p>
<h2>Features</h2>
<ul>
<li>Drag-and-drop interface for building threat models.</li>
<li>Automatic threat analysis and risk scoring.</li>
<li>Integration with other security tools and frameworks.</li>
<li>Export models to various formats (PDF, HTML, JSON).</li>
<li>Collaborative features for team-based threat modeling.</li>
</ul>
<h2>Learn More</h2>
<p>For more information, visit the official <a href="https://owasp.org/www-project-threat-dragon/">OWASP Threat Dragon Project Page</a>.</p>
<p>Visit our <a href="https://github.com/owasp/threat-dragon/">GitHub repository</a> for source code, bug reports, and contributing guidelines.</p>
<p>If you encounter any issues or have suggestions, feel free to <a href="https://github.com/owasp/threat-dragon/issues">submit an issue</a> or create a <a href="https://github.com/owasp/threat-dragon/pulls">pull request</a>.</p>
</body>
</html>
`;

// Load the content directly into the window
aboutWin.loadURL('data:text/html;charset=utf-8,' + encodeURIComponent(aboutContent));

// Optional: Open DevTools to debug
aboutWin.webContents.openDevTools();

// Optional: Log load success
aboutWin.webContents.on('did-finish-load', () => {
console.log('About page content loaded');
});
}
},
...(process.platform === 'darwin' && { role: 'about' }) // Only add 'role: about' for macOS
}
,

// { role: 'about' }
]
}
);
Expand All @@ -178,7 +257,7 @@ export function getMenuTemplate () {
}

// Open file system dialog and read file contents into model
function openModel (filename) {
function openModel(filename) {
logger.log.debug('Open file with name : ' + filename);

if (filename !== '') {
Expand Down Expand Up @@ -207,13 +286,13 @@ function openModel (filename) {
}

// request to the renderer for confirmation that it is OK to open a model file
function openModelRequest (filename) {
function openModelRequest(filename) {
logger.log.debug('Request to renderer to open an existing model');
mainWindow.webContents.send('open-model-request', filename);
}

// request to the renderer for confirmation that it is OK to open a model file
function openModelFile (filename) {
function openModelFile(filename) {
logger.log.debug(messages[language].desktop.file.open + ': ' + filename);
fs.readFile(filename, (err, data) => {
if (!err) {
Expand All @@ -231,7 +310,7 @@ function openModelFile (filename) {
}

// request that the renderer send the model data, retain existing filename
function saveModel () {
function saveModel() {
if (model.isOpen === false) {
logger.log.debug('Skip save request because no model is open');
return;
Expand All @@ -241,7 +320,7 @@ function saveModel () {
}

// request that the renderer send the model data
function saveModelAs () {
function saveModelAs() {
if (model.isOpen === false) {
logger.log.debug('Skip saveAs request because no model is open');
return;
Expand All @@ -253,7 +332,7 @@ function saveModelAs () {
}

// Open saveAs file system dialog and write contents to new file location
function saveModelDataAs (modelData, fileName) {
function saveModelDataAs(modelData, fileName) {
let newName = 'new-model.json';
if (fileName) {
newName = fileName;
Expand Down Expand Up @@ -282,31 +361,31 @@ function saveModelDataAs (modelData, fileName) {
}

// request that the renderer open a new model
function newModel () {
function newModel() {
let newName = 'new-model.json';
logger.log.debug(messages[language].desktop.file.new + ': ' + newName);
mainWindow.webContents.send('new-model-request', newName);
}

// request that the renderer display the model report/print page
function printModel (format) {
function printModel(format) {
if (model.isOpen === false) {
logger.log.debug('Skip print request because no model open');
return;
}
logger.log.debug(messages[language].forms.exportPdf+ ': ' + model.filePath);
logger.log.debug(messages[language].forms.exportPdf + ': ' + model.filePath);
// prompt the renderer to open the print/report window
mainWindow.webContents.send('print-model-request', format);
}

// request that the renderer close the model
function closeModelRequest () {
function closeModelRequest() {
logger.log.debug(messages[language].desktop.file.close + ': ' + model.filePath);
mainWindow.webContents.send('close-model-request', path.basename(model.filePath));
}

// save the threat model
function saveModelData (modelData) {
function saveModelData(modelData) {
if (model.isOpen === true) {
fs.writeFile(model.filePath, JSON.stringify(modelData, undefined, 2), (err) => {
if (err) {
Expand All @@ -322,7 +401,7 @@ function saveModelData (modelData) {
}

// Open saveAs file system dialog and write report contents as HTML
function saveHTMLReport (htmlPath) {
function saveHTMLReport(htmlPath) {
htmlPath += '.html';
var dialogOptions = {
title: messages[language].forms.saveAS,
Expand All @@ -347,7 +426,7 @@ function saveHTMLReport (htmlPath) {
}

// Open saveAs file system dialog and write PDF report
function savePDFReport (pdfPath) {
function savePDFReport(pdfPath) {
pdfPath += '.pdf';
var dialogOptions = {
title: messages[language].forms.exportPdf,
Expand Down
Loading