Compare commits
30 commits
Author | SHA1 | Date | |
---|---|---|---|
|
d8b4a139ac | ||
|
9f4771bf26 | ||
|
552b97eec5 | ||
|
6c0f00170c | ||
|
e3b9a839f5 | ||
|
238b07b7dd | ||
|
9dc1e422ff | ||
|
ebe7427385 | ||
|
3e3bee2062 | ||
|
c93b6878a9 | ||
|
d2e26ef5d1 | ||
|
c41befae64 | ||
|
8b720750db | ||
|
ee317ec5aa | ||
|
d7c657e671 | ||
|
7a8a54c76b | ||
|
c29f98b6bc | ||
|
8d1847a8d1 | ||
|
194f4fabaf | ||
|
3f4a5e97fa | ||
|
3eb789d055 | ||
|
8a8f064864 | ||
|
58add05655 | ||
|
0a400d915f | ||
|
f615e7754c | ||
|
92717c8047 | ||
|
045b83f843 | ||
|
1dd3b76187 | ||
|
4b1dd6146c | ||
|
3601599ff1 |
|
@ -1,49 +0,0 @@
|
||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- nodejs_version: "10"
|
|
||||||
|
|
||||||
init:
|
|
||||||
- git config --global core.symlinks true
|
|
||||||
|
|
||||||
install:
|
|
||||||
# Setup the code signing certificate
|
|
||||||
- ps: >-
|
|
||||||
if (Test-Path Env:\WINDOWS_CERTIFICATE_P12) {
|
|
||||||
$workingDirectory = Convert-Path (Resolve-Path -path ".")
|
|
||||||
$filename = "$workingDirectory\cert.p12"
|
|
||||||
$bytes = [Convert]::FromBase64String($env:WINDOWS_CERTIFICATE_P12)
|
|
||||||
[IO.File]::WriteAllBytes($filename, $bytes)
|
|
||||||
$env:WINDOWS_CERTIFICATE_FILE = $filename
|
|
||||||
$sec = ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText
|
|
||||||
$cert = Get-PfxData -Password $sec $filename
|
|
||||||
Write-Host $cert.EndEntityCertificates
|
|
||||||
}
|
|
||||||
- ps: Install-Product node $env:nodejs_version x64
|
|
||||||
- node --version
|
|
||||||
- npm ci
|
|
||||||
- ps: mkdir images
|
|
||||||
- ps: cd images
|
|
||||||
- ps: Start-FileDownload 'https://1drv.ws/u/s!AkfaAw_EaahOkulh8rA41x2phgfYXQ' -FileName images.zip -Timeout 600000
|
|
||||||
- ps: 7z x images.zip -y -aoa
|
|
||||||
- ps: Remove-Item images.zip
|
|
||||||
- ps: Remove-Item __MACOSX -Recurse -ErrorAction Ignore
|
|
||||||
- ps: cd ..
|
|
||||||
- ps: Tree ./src /F
|
|
||||||
- ps: Tree ./images /F
|
|
||||||
|
|
||||||
cache:
|
|
||||||
- '%APPDATA%\npm-cache -> appveyor.yml'
|
|
||||||
|
|
||||||
test_script:
|
|
||||||
- node --version
|
|
||||||
- npm --version
|
|
||||||
- npm run lint
|
|
||||||
|
|
||||||
artifacts:
|
|
||||||
- path: 'out\make\squirrel.windows\**\*.exe'
|
|
||||||
|
|
||||||
build_script:
|
|
||||||
- if %APPVEYOR_REPO_TAG% EQU false npm run make
|
|
||||||
- if %APPVEYOR_REPO_TAG% EQU true npm run publish
|
|
||||||
- if %APPVEYOR_REPO_TAG% EQU true npm run publish -- --arch=ia32
|
|
||||||
- ps: Tree ./out/make /F
|
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
text eol=lf
|
BIN
.github/images/linux.png
vendored
Normal file
BIN
.github/images/linux.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
BIN
.github/images/macos.png
vendored
Normal file
BIN
.github/images/macos.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
BIN
.github/images/windows.png
vendored
Normal file
BIN
.github/images/windows.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
109
.github/workflows/build.yml
vendored
Normal file
109
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
name: Build & Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 15.x
|
||||||
|
- name: Get yarn cache directory path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- uses: actions/cache@v1
|
||||||
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
|
- name: Install
|
||||||
|
run: yarn
|
||||||
|
- name: lint
|
||||||
|
run: yarn lint
|
||||||
|
build:
|
||||||
|
needs: lint
|
||||||
|
name: Build (${{ matrix.os }})
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ macOS-latest, ubuntu-latest, windows-latest ]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 12.x
|
||||||
|
- name: Get yarn cache directory path
|
||||||
|
id: yarn-cache-dir-path
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
- uses: actions/cache@v1
|
||||||
|
if: matrix.os != 'macOS-latest'
|
||||||
|
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
|
- name: Set MacOS signing certs
|
||||||
|
if: matrix.os == 'macOS-latest'
|
||||||
|
run: chmod +x tools/add-macos-cert.sh && ./tools/add-macos-cert.sh
|
||||||
|
env:
|
||||||
|
MACOS_CERT_P12: ${{ secrets.MACOS_CERT_P12 }}
|
||||||
|
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
|
||||||
|
- name: Set Windows signing certificate
|
||||||
|
if: matrix.os == 'windows-latest'
|
||||||
|
continue-on-error: true
|
||||||
|
id: write_file
|
||||||
|
uses: timheuer/base64-to-file@v1
|
||||||
|
with:
|
||||||
|
fileName: 'win-certificate.pfx'
|
||||||
|
encodedString: ${{ secrets.WINDOWS_CODESIGN_P12 }}
|
||||||
|
- name: Download disk image (ps1)
|
||||||
|
run: tools/download-disk.ps1
|
||||||
|
if: matrix.os == 'windows-latest' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
env:
|
||||||
|
DISK_URL: ${{ secrets.DISK_URL }}
|
||||||
|
- name: Download disk image (sh)
|
||||||
|
run: chmod +x tools/download-disk.sh && ./tools/download-disk.sh
|
||||||
|
if: matrix.os != 'windows-latest' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
env:
|
||||||
|
DISK_URL: ${{ secrets.DISK_URL }}
|
||||||
|
- name: Install
|
||||||
|
run: yarn
|
||||||
|
- name: Make
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
run: yarn make --arch=all
|
||||||
|
env:
|
||||||
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
|
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||||
|
WINDOWS_CODESIGN_FILE: ${{ steps.write_file.outputs.filePath }}
|
||||||
|
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
|
||||||
|
# - name: Archive production artifacts
|
||||||
|
# uses: actions/upload-artifact@v2
|
||||||
|
# with:
|
||||||
|
# name: ${{ matrix.os }}
|
||||||
|
# path: out/make/**/*
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
draft: true
|
||||||
|
files: |
|
||||||
|
out/**/*.deb
|
||||||
|
out/**/*.dmg
|
||||||
|
out/**/*setup*.exe
|
||||||
|
out/**/*.rpm
|
||||||
|
out/**/*.zip
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,4 +3,5 @@ out
|
||||||
src/images
|
src/images
|
||||||
.DS_Store
|
.DS_Store
|
||||||
images
|
images
|
||||||
dist
|
dist
|
||||||
|
!.github/images
|
64
.travis.yml
64
.travis.yml
|
@ -1,64 +0,0 @@
|
||||||
language: node_js
|
|
||||||
node_js: "12"
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
- osx
|
|
||||||
dist: trusty
|
|
||||||
osx_image: xcode10
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
- $HOME/.cache/electron
|
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- fakeroot
|
|
||||||
- rpm
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- master
|
|
||||||
- /^v\d+\.\d+\.\d+/
|
|
||||||
|
|
||||||
install:
|
|
||||||
- npm install
|
|
||||||
- mkdir -p ./images
|
|
||||||
- cd ./images
|
|
||||||
- wget -O images.zip https://1drv.ws/u/s!AkfaAw_EaahOkulh8rA41x2phgfYXQ
|
|
||||||
- unzip -o images.zip
|
|
||||||
- rm images.zip
|
|
||||||
- rm -r __MACOSX
|
|
||||||
- cd ..
|
|
||||||
- ls src
|
|
||||||
- ls images
|
|
||||||
- |
|
|
||||||
if [[ "$TRAVIS_OS_NAME" == "osx" && "$TRAVIS_SECURE_ENV_VARS" == "true" ]]; then
|
|
||||||
export CERTIFICATE_P12=cert.p12;
|
|
||||||
echo $MACOS_CERT_P12 | base64 --decode > $CERTIFICATE_P12;
|
|
||||||
export KEYCHAIN=build.keychain;
|
|
||||||
# Create the keychain with a password
|
|
||||||
security create-keychain -p travis $KEYCHAIN;
|
|
||||||
# Make the custom keychain default, so xcodebuild will use it for signing
|
|
||||||
security default-keychain -s $KEYCHAIN;
|
|
||||||
# Unlock the keychain
|
|
||||||
security unlock-keychain -p travis $KEYCHAIN;
|
|
||||||
# Add certificates to keychain and allow codesign to access them
|
|
||||||
# Apple Worldwide Developer Relations Certification Authority
|
|
||||||
security import ./assets/certs/apple.cer -k ~/Library/Keychains/$KEYCHAIN -T /usr/bin/codesign
|
|
||||||
# Developer Authentication Certification Authority
|
|
||||||
security import ./assets/certs/dac.cer -k ~/Library/Keychains/$KEYCHAIN -T /usr/bin/codesign
|
|
||||||
# Developer ID Felix
|
|
||||||
security import $CERTIFICATE_P12 -k $KEYCHAIN -P $MACOS_CERT_PASSWORD -T /usr/bin/codesign 2>&1 >/dev/null;
|
|
||||||
rm $CERTIFICATE_P12;
|
|
||||||
security set-key-partition-list -S apple-tool:,apple: -s -k travis $KEYCHAIN
|
|
||||||
# Echo the identity
|
|
||||||
security find-identity -v -p codesigning
|
|
||||||
fi
|
|
||||||
script:
|
|
||||||
- npm run lint
|
|
||||||
- if test -z "$TRAVIS_TAG"; then npm run make; fi
|
|
||||||
|
|
||||||
after_success: if test -n "$TRAVIS_TAG"; then npm run publish; fi
|
|
9
HELP.md
9
HELP.md
|
@ -1,10 +1,10 @@
|
||||||
# Help & Commonly Asked Questions
|
# Help & Commonly Asked Questions
|
||||||
|
|
||||||
## MS-DOS seems to brick the screen
|
## MS-DOS seems to mess up the screen
|
||||||
Hit `Alt + Enter` to make the command screen "full screen" (as far as Windows 95 is
|
Hit `Alt + Enter` to make the command screen "Full Screen" (as far as Windows 95 is
|
||||||
concerned). This should restore the display from the garbled mess you see and allow
|
concerned). This should restore the display from the garbled mess you see and allow
|
||||||
you to access the command prompt. Press Alt-Enter again to leave full screen and go
|
you to access the Command Prompt. Press Alt-Enter again to leave Full Screen and go
|
||||||
back to a window mode. (Thanks to @DisplacedGamer for that wisdom)
|
back to Window Mode. (Thanks to @DisplacedGamers for that wisdom)
|
||||||
|
|
||||||
## Windows 95 is stuck in a bad state
|
## Windows 95 is stuck in a bad state
|
||||||
|
|
||||||
|
@ -31,4 +31,5 @@ with the image as input.
|
||||||
|
|
||||||
## What's the FrontPage Username and Password?
|
## What's the FrontPage Username and Password?
|
||||||
Username: windows95
|
Username: windows95
|
||||||
|
|
||||||
Password: password
|
Password: password
|
||||||
|
|
100
README.md
100
README.md
|
@ -3,10 +3,102 @@
|
||||||
This is Windows 95, running in an [Electron](https://electronjs.org/) app. Yes, it's the full thing. I'm sorry.
|
This is Windows 95, running in an [Electron](https://electronjs.org/) app. Yes, it's the full thing. I'm sorry.
|
||||||
|
|
||||||
## Downloads
|
## Downloads
|
||||||
| | Windows | macOS | Linux |
|
|
||||||
|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
<table class="is-fullwidth">
|
||||||
| Standalone Download | 📦[Standalone, 32-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-win32-standalone-ia32.zip) <br /> 📦[Standalone, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-win32-standalone-x64.zip) | 📦[Standalone](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-macos-2.2.0.zip) | |
|
</thead>
|
||||||
| Installer | 💽[Setup, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-setup-win32-x64.exe) <br /> 💽[Setup, 32-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-2.2.0-setup-win32-ia32.exe) | | 💽[deb, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-linux-2.2.0_amd64.deb) <br /> 💽[rpm, 64-bit](https://github.com/felixrieseberg/windows95/releases/download/v2.2.0/windows95-linux-2.2.0.x86_64.rpm) |
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="./.github/images/windows.png" width="24"><br />
|
||||||
|
Windows
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span>32-bit</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-setup-ia32.exe">
|
||||||
|
💿 Installer
|
||||||
|
</a> |
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-win32-ia32-2.3.0.zip">
|
||||||
|
📦 Standalone Zip
|
||||||
|
</a>
|
||||||
|
<br />
|
||||||
|
<span>64-bit</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-setup-x64.exe">
|
||||||
|
💿 Installer
|
||||||
|
</a> |
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-win32-ia32-2.3.0.zip">
|
||||||
|
📦 Standalone Zip
|
||||||
|
</a><br />
|
||||||
|
<span>ARM64</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-setup-arm64.exe">
|
||||||
|
💿 Installer
|
||||||
|
</a> |
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-win32-ia32-2.3.0.zip">
|
||||||
|
📦 Standalone Zip
|
||||||
|
</a><br />
|
||||||
|
<span>
|
||||||
|
❓ Don't know what kind of chip you have? Hit start, enter "processor" for info.
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="./.github/images/macos.png" width="24"><br />
|
||||||
|
macOS
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span>Intel Processor</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-darwin-x64-2.3.0.zip">
|
||||||
|
📦 Standalone Zip
|
||||||
|
</a><br />
|
||||||
|
<span>Apple M1 Processor</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-darwin-arm64-2.3.0.zip">
|
||||||
|
📦 Standalone Zip
|
||||||
|
</a><br />
|
||||||
|
<span>
|
||||||
|
❓ Don't know what kind of chip you have? Learn more at <a href="https://support.apple.com/en-us/HT211814">apple.com</a>.
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<img src="./.github/images/linux.png" width="24"><br />
|
||||||
|
Linux
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span>32-bit</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.i386.rpm">
|
||||||
|
💿 rpm
|
||||||
|
</a> |
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_i386.deb">
|
||||||
|
💿 deb
|
||||||
|
</a><br />
|
||||||
|
<span>64-bit</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.x86_64.rpm">
|
||||||
|
💿 rpm
|
||||||
|
</a> |
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_amd64.deb">
|
||||||
|
💿 deb
|
||||||
|
</a><br />
|
||||||
|
<span>ARM64</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.arm64.rpm">
|
||||||
|
💿 rpm
|
||||||
|
</a> |
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_arm64.deb">
|
||||||
|
💿 deb
|
||||||
|
</a><br />
|
||||||
|
<span>ARMv7 (armhf)</span>
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95-2.3.0-1.arm64.rpm">
|
||||||
|
💿 rpm
|
||||||
|
</a> |
|
||||||
|
<a href="https://github.com/felixrieseberg/windows95/releases/download/v2.3.0/windows95_2.3.0_armhf.deb">
|
||||||
|
💿 deb
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
![Screenshot](https://user-images.githubusercontent.com/1426799/44532591-4ceb3680-a6a8-11e8-8c2c-bc29f3bfdef7.png)
|
![Screenshot](https://user-images.githubusercontent.com/1426799/44532591-4ceb3680-a6a8-11e8-8c2c-bc29f3bfdef7.png)
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
16
assets/entitlements.plist
Normal file
16
assets/entitlements.plist
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.disable-library-validation</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.cs.disable-executable-page-protection</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.automation.apple-events</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -1,10 +1,19 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
const package = require('./package.json');
|
const package = require('./package.json');
|
||||||
|
|
||||||
|
if (process.env['WINDOWS_CODESIGN_FILE']) {
|
||||||
|
const certPath = path.join(__dirname, 'win-certificate.pfx');
|
||||||
|
const certExists = fs.existsSync(certPath);
|
||||||
|
|
||||||
|
if (certExists) {
|
||||||
|
process.env['WINDOWS_CODESIGN_FILE'] = certPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
hooks: {
|
hooks: {
|
||||||
generateAssets: require('./tools/generateAssets'),
|
generateAssets: require('./tools/generateAssets'),
|
||||||
postPackage: require('./tools/notarize')
|
|
||||||
},
|
},
|
||||||
packagerConfig: {
|
packagerConfig: {
|
||||||
asar: false,
|
asar: false,
|
||||||
|
@ -19,10 +28,16 @@ module.exports = {
|
||||||
identity: 'Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)',
|
identity: 'Developer ID Application: Felix Rieseberg (LT94ZKYDCJ)',
|
||||||
'hardened-runtime': true,
|
'hardened-runtime': true,
|
||||||
'gatekeeper-assess': false,
|
'gatekeeper-assess': false,
|
||||||
'entitlements': 'static/entitlements.plist',
|
'entitlements': 'assets/entitlements.plist',
|
||||||
'entitlements-inherit': 'static/entitlements.plist',
|
'entitlements-inherit': 'assets/entitlements.plist',
|
||||||
'signature-flags': 'library'
|
'signature-flags': 'library'
|
||||||
},
|
},
|
||||||
|
osxNotarize: {
|
||||||
|
appBundleId: 'com.felixrieseberg.macintoshjs',
|
||||||
|
appleId: process.env['APPLE_ID'],
|
||||||
|
appleIdPassword: process.env['APPLE_ID_PASSWORD'],
|
||||||
|
ascProvider: 'LT94ZKYDCJ'
|
||||||
|
},
|
||||||
ignore: [
|
ignore: [
|
||||||
/\/assets(\/?)/,
|
/\/assets(\/?)/,
|
||||||
/\/docs(\/?)/,
|
/\/docs(\/?)/,
|
||||||
|
@ -49,8 +64,8 @@ module.exports = {
|
||||||
remoteReleases: '',
|
remoteReleases: '',
|
||||||
setupExe: `windows95-${package.version}-setup-${arch}.exe`,
|
setupExe: `windows95-${package.version}-setup-${arch}.exe`,
|
||||||
setupIcon: path.resolve(__dirname, 'assets', 'icon.ico'),
|
setupIcon: path.resolve(__dirname, 'assets', 'icon.ico'),
|
||||||
certificateFile: process.env.WINDOWS_CERTIFICATE_FILE,
|
certificateFile: process.env['WINDOWS_CODESIGN_FILE'],
|
||||||
certificatePassword: process.env.WINDOWS_CERTIFICATE_PASSWORD
|
certificatePassword: process.env['WINDOWS_CODESIGN_PASSWORD'],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -66,18 +81,5 @@ module.exports = {
|
||||||
name: '@electron-forge/maker-rpm',
|
name: '@electron-forge/maker-rpm',
|
||||||
platforms: ['linux']
|
platforms: ['linux']
|
||||||
}
|
}
|
||||||
],
|
|
||||||
publishers: [
|
|
||||||
{
|
|
||||||
name: '@electron-forge/publisher-github',
|
|
||||||
config: {
|
|
||||||
repository: {
|
|
||||||
owner: 'felixrieseberg',
|
|
||||||
name: 'windows95'
|
|
||||||
},
|
|
||||||
draft: true,
|
|
||||||
prerelease: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
11965
package-lock.json
generated
11965
package-lock.json
generated
File diff suppressed because it is too large
Load diff
55
package.json
55
package.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "windows95",
|
"name": "windows95",
|
||||||
"productName": "windows95",
|
"productName": "windows95",
|
||||||
"version": "2.2.1",
|
"version": "2.3.0",
|
||||||
"description": "Windows 95, in an app. I'm sorry.",
|
"description": "Windows 95, in an app. I'm sorry.",
|
||||||
"main": "./dist/src/main/main",
|
"main": "./dist/src/main/main",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -9,8 +9,10 @@
|
||||||
"package": "electron-forge package",
|
"package": "electron-forge package",
|
||||||
"make": "electron-forge make",
|
"make": "electron-forge make",
|
||||||
"publish": "electron-forge publish",
|
"publish": "electron-forge publish",
|
||||||
"lint": "prettier --write src/**/*.{ts,tsx}",
|
"lint": "prettier --write src/**/*.{ts,tsx} && npm run check-links",
|
||||||
"less": "node ./tools/lessc.js"
|
"less": "node ./tools/lessc.js",
|
||||||
|
"tsc": "tsc -p tsconfig.json --noEmit",
|
||||||
|
"check-links": "node tools/check-links.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Felix Rieseberg, felix@felixrieseberg.com",
|
"author": "Felix Rieseberg, felix@felixrieseberg.com",
|
||||||
|
@ -20,32 +22,31 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-squirrel-startup": "^1.0.0",
|
"electron-squirrel-startup": "^1.0.0",
|
||||||
"fs-extra": "^8.1.0",
|
"fs-extra": "^9.0.1",
|
||||||
"react": "^16.12.0",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^17.0.1",
|
||||||
"tslib": "^1.10.0",
|
"tslib": "^2.0.3",
|
||||||
"update-electron-app": "^1.5.0"
|
"update-electron-app": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron-forge/cli": "^6.0.0-beta.45",
|
"@electron-forge/cli": "^6.0.0-beta.54",
|
||||||
"@electron-forge/maker-deb": "^6.0.0-beta.45",
|
"@electron-forge/maker-deb": "^6.0.0-beta.54",
|
||||||
"@electron-forge/maker-flatpak": "^6.0.0-beta.45",
|
"@electron-forge/maker-flatpak": "^6.0.0-beta.54",
|
||||||
"@electron-forge/maker-rpm": "^6.0.0-beta.45",
|
"@electron-forge/maker-rpm": "^6.0.0-beta.54",
|
||||||
"@electron-forge/maker-squirrel": "^6.0.0-beta.45",
|
"@electron-forge/maker-squirrel": "^6.0.0-beta.54",
|
||||||
"@electron-forge/maker-zip": "^6.0.0-beta.45",
|
"@electron-forge/maker-zip": "^6.0.0-beta.54",
|
||||||
"@electron-forge/publisher-github": "^6.0.0-beta.45",
|
"@electron-forge/publisher-github": "^6.0.0-beta.54",
|
||||||
"@types/fs-extra": "^8.0.1",
|
"@types/fs-extra": "^9.0.5",
|
||||||
"@types/node": "^12.12.14",
|
"@types/node": "^12.19.9",
|
||||||
"@types/react": "^16.9.13",
|
"@types/react": "^17.0.0",
|
||||||
"@types/react-dom": "^16.9.4",
|
"@types/react-dom": "^17.0.0",
|
||||||
"electron": "7.1.2",
|
"electron": "11.1.1",
|
||||||
"electron-notarize": "^0.2.1",
|
"less": "^3.13.0",
|
||||||
"less": "^3.10.3",
|
"node-abi": "^2.19.3",
|
||||||
"node-abi": "^2.13.0",
|
|
||||||
"parcel-bundler": "^1.12.4",
|
"parcel-bundler": "^1.12.4",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^2.2.1",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.2",
|
||||||
"standard": "^14.3.1",
|
"standard": "^16.0.3",
|
||||||
"typescript": "^3.7.2"
|
"typescript": "^4.1.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
33
src/cache.ts
33
src/cache.ts
|
@ -1,8 +1,8 @@
|
||||||
import { session } from 'electron';
|
import { session } from "electron";
|
||||||
|
|
||||||
export async function clearCaches() {
|
export async function clearCaches() {
|
||||||
await clearCache()
|
await clearCache();
|
||||||
await clearStorageData()
|
await clearStorageData();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clearCache() {
|
export async function clearCache() {
|
||||||
|
@ -11,15 +11,22 @@ export async function clearCache() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearStorageData() {
|
export async function clearStorageData() {
|
||||||
return new Promise((resolve) => {
|
if (!session.defaultSession) {
|
||||||
if (!session.defaultSession) {
|
return;
|
||||||
return resolve();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
session.defaultSession.clearStorageData({
|
await session.defaultSession.clearStorageData({
|
||||||
storages: [ 'appcache', 'cookies', 'filesystem', 'indexdb', 'localstorage', 'shadercache', 'websql', 'serviceworkers' ],
|
storages: [
|
||||||
quotas: [ 'temporary', 'persistent', 'syncable' ]
|
"appcache",
|
||||||
}, resolve)
|
"cookies",
|
||||||
})
|
"filesystem",
|
||||||
|
"indexdb",
|
||||||
|
"localstorage",
|
||||||
|
"shadercache",
|
||||||
|
"websql",
|
||||||
|
"serviceworkers",
|
||||||
|
],
|
||||||
|
quotas: ["temporary", "persistent", "syncable"],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,30 @@
|
||||||
import { remote, app } from 'electron';
|
import * as path from "path";
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
const _app = app || remote.app
|
|
||||||
|
|
||||||
export const CONSTANTS = {
|
export const CONSTANTS = {
|
||||||
IMAGE_PATH: path.join(__dirname, '../../images/windows95.img'),
|
IMAGE_PATH: path.join(__dirname, "../../images/windows95.img"),
|
||||||
IMAGE_DEFAULT_SIZE: 1073741824, // 1GB
|
IMAGE_DEFAULT_SIZE: 1073741824, // 1GB
|
||||||
DEFAULT_STATE_PATH: path.join(__dirname, '../../images/default-state.bin'),
|
DEFAULT_STATE_PATH: path.join(__dirname, "../../images/default-state.bin"),
|
||||||
STATE_PATH: path.join(_app.getPath('userData'), 'state-v2.bin')
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export const IPC_COMMANDS = {
|
export const IPC_COMMANDS = {
|
||||||
TOGGLE_INFO: 'TOGGLE_INFO',
|
TOGGLE_INFO: "TOGGLE_INFO",
|
||||||
SHOW_DISK_IMAGE: 'SHOW_DISK_IMAGE',
|
SHOW_DISK_IMAGE: "SHOW_DISK_IMAGE",
|
||||||
ZOOM_IN: 'ZOOM_IN',
|
ZOOM_IN: "ZOOM_IN",
|
||||||
ZOOM_OUT: 'ZOOM_OUT',
|
ZOOM_OUT: "ZOOM_OUT",
|
||||||
ZOOM_RESET: 'ZOOM_RESET',
|
ZOOM_RESET: "ZOOM_RESET",
|
||||||
// Machine instructions
|
// Machine instructions
|
||||||
MACHINE_START: 'MACHINE_START',
|
MACHINE_START: "MACHINE_START",
|
||||||
MACHINE_RESTART: 'MACHINE_RESTART',
|
MACHINE_RESTART: "MACHINE_RESTART",
|
||||||
MACHINE_STOP: 'MACHINE_STOP',
|
MACHINE_STOP: "MACHINE_STOP",
|
||||||
MACHINE_RESET: 'MACHINE_RESET',
|
MACHINE_RESET: "MACHINE_RESET",
|
||||||
MACHINE_ALT_F4: 'MACHINE_ALT_F4',
|
MACHINE_ALT_F4: "MACHINE_ALT_F4",
|
||||||
MACHINE_ESC: 'MACHINE_ESC',
|
MACHINE_ESC: "MACHINE_ESC",
|
||||||
MACHINE_ALT_ENTER: 'MACHINE_ALT_ENTER',
|
MACHINE_ALT_ENTER: "MACHINE_ALT_ENTER",
|
||||||
MACHINE_CTRL_ALT_DEL: 'MACHINE_CTRL_ALT_DEL',
|
MACHINE_CTRL_ALT_DEL: "MACHINE_CTRL_ALT_DEL",
|
||||||
// Machine events
|
// Machine events
|
||||||
MACHINE_STARTED: 'MACHINE_STARTED',
|
MACHINE_STARTED: "MACHINE_STARTED",
|
||||||
MACHINE_STOPPED: 'MACHINE_STOPPED'
|
MACHINE_STOPPED: "MACHINE_STOPPED",
|
||||||
}
|
// Else
|
||||||
|
APP_QUIT: "APP_QUIT",
|
||||||
|
GET_STATE_PATH: "GET_STATE_PATH",
|
||||||
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ export function setupAboutPanel(): void {
|
||||||
applicationName: "windows95",
|
applicationName: "windows95",
|
||||||
applicationVersion: app.getVersion(),
|
applicationVersion: app.getVersion(),
|
||||||
version: process.versions.electron,
|
version: process.versions.electron,
|
||||||
copyright: "Felix Rieseberg"
|
copyright: "Felix Rieseberg",
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
|
|
14
src/main/ipc.ts
Normal file
14
src/main/ipc.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { ipcMain, app } from "electron";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
import { IPC_COMMANDS } from "../constants";
|
||||||
|
|
||||||
|
export function setupIpcListeners() {
|
||||||
|
ipcMain.handle(IPC_COMMANDS.GET_STATE_PATH, () => {
|
||||||
|
return path.join(app.getPath("userData"), "state-v2.bin");
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle(IPC_COMMANDS.APP_QUIT, () => {
|
||||||
|
app.quit();
|
||||||
|
});
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import { shouldQuit } from "./squirrel";
|
||||||
import { setupUpdates } from "./update";
|
import { setupUpdates } from "./update";
|
||||||
import { getOrCreateWindow } from "./windows";
|
import { getOrCreateWindow } from "./windows";
|
||||||
import { setupMenu } from "./menu";
|
import { setupMenu } from "./menu";
|
||||||
|
import { setupIpcListeners } from "./ipc";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the app's "ready" event. This is essentially
|
* Handle the app's "ready" event. This is essentially
|
||||||
|
@ -14,6 +15,7 @@ import { setupMenu } from "./menu";
|
||||||
export async function onReady() {
|
export async function onReady() {
|
||||||
if (!isDevMode()) process.env.NODE_ENV = "production";
|
if (!isDevMode()) process.env.NODE_ENV = "production";
|
||||||
|
|
||||||
|
setupIpcListeners();
|
||||||
getOrCreateWindow();
|
getOrCreateWindow();
|
||||||
setupAboutPanel();
|
setupAboutPanel();
|
||||||
setupMenu();
|
setupMenu();
|
||||||
|
|
115
src/main/menu.ts
115
src/main/menu.ts
|
@ -1,15 +1,14 @@
|
||||||
import { app, shell, Menu, BrowserWindow, ipcMain, webFrame } from "electron";
|
import { app, shell, Menu, BrowserWindow, ipcMain } from "electron";
|
||||||
|
|
||||||
import { clearCaches } from "../cache";
|
import { clearCaches } from "../cache";
|
||||||
import { IPC_COMMANDS } from "../constants";
|
import { IPC_COMMANDS } from "../constants";
|
||||||
import { isDevMode } from "../utils/devmode";
|
import { isDevMode } from "../utils/devmode";
|
||||||
import { getOrCreateWindow } from "./windows";
|
|
||||||
|
|
||||||
const LINKS = {
|
const LINKS = {
|
||||||
homepage: "https://www.twitter.com/felixrieseberg",
|
homepage: "https://www.twitter.com/felixrieseberg",
|
||||||
repo: "https://github.com/felixrieseberg/windows95",
|
repo: "https://github.com/felixrieseberg/windows95",
|
||||||
credits: "https://github.com/felixrieseberg/windows95/blob/master/CREDITS.md",
|
credits: "https://github.com/felixrieseberg/windows95/blob/master/CREDITS.md",
|
||||||
help: "https://github.com/felixrieseberg/windows95/blob/master/HELP.md"
|
help: "https://github.com/felixrieseberg/windows95/blob/master/HELP.md",
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function setupMenu() {
|
export async function setupMenu() {
|
||||||
|
@ -41,52 +40,52 @@ async function createMenu({ isRunning } = { isRunning: false }) {
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: "Toggle Full Screen",
|
label: "Toggle Full Screen",
|
||||||
accelerator: (function() {
|
accelerator: (function () {
|
||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
return "Ctrl+Command+F";
|
return "Ctrl+Command+F";
|
||||||
} else {
|
} else {
|
||||||
return "F11";
|
return "F11";
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
click: function(_item, focusedWindow) {
|
click: function (_item, focusedWindow) {
|
||||||
if (focusedWindow) {
|
if (focusedWindow) {
|
||||||
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Toggle Developer Tools",
|
label: "Toggle Developer Tools",
|
||||||
accelerator: (function() {
|
accelerator: (function () {
|
||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
return "Alt+Command+I";
|
return "Alt+Command+I";
|
||||||
} else {
|
} else {
|
||||||
return "Ctrl+Shift+I";
|
return "Ctrl+Shift+I";
|
||||||
}
|
}
|
||||||
})(),
|
})(),
|
||||||
click: function(_item, focusedWindow) {
|
click: function (_item, focusedWindow) {
|
||||||
if (focusedWindow) {
|
if (focusedWindow) {
|
||||||
focusedWindow.webContents.toggleDevTools();
|
focusedWindow.webContents.toggleDevTools();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Toggle Emulator Info",
|
label: "Toggle Emulator Info",
|
||||||
click: () => send(IPC_COMMANDS.TOGGLE_INFO)
|
click: () => send(IPC_COMMANDS.TOGGLE_INFO),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "reload"
|
role: "reload",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "editMenu",
|
role: "editMenu",
|
||||||
visible: isDevMode()
|
visible: isDevMode(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Window",
|
label: "Window",
|
||||||
|
@ -95,32 +94,32 @@ async function createMenu({ isRunning } = { isRunning: false }) {
|
||||||
{
|
{
|
||||||
label: "Minimize",
|
label: "Minimize",
|
||||||
accelerator: "CmdOrCtrl+M",
|
accelerator: "CmdOrCtrl+M",
|
||||||
role: "minimize"
|
role: "minimize",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Close",
|
label: "Close",
|
||||||
accelerator: "CmdOrCtrl+W",
|
accelerator: "CmdOrCtrl+W",
|
||||||
role: "close"
|
role: "close",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Zoom in",
|
label: "Zoom in",
|
||||||
click: () => send(IPC_COMMANDS.ZOOM_IN),
|
click: () => send(IPC_COMMANDS.ZOOM_IN),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Zoom out",
|
label: "Zoom out",
|
||||||
click: () => send(IPC_COMMANDS.ZOOM_OUT),
|
click: () => send(IPC_COMMANDS.ZOOM_OUT),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Reset zoom",
|
label: "Reset zoom",
|
||||||
click: () => send(IPC_COMMANDS.ZOOM_RESET),
|
click: () => send(IPC_COMMANDS.ZOOM_RESET),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Machine",
|
label: "Machine",
|
||||||
|
@ -128,53 +127,53 @@ async function createMenu({ isRunning } = { isRunning: false }) {
|
||||||
{
|
{
|
||||||
label: "Send Ctrl+Alt+Del",
|
label: "Send Ctrl+Alt+Del",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_CTRL_ALT_DEL),
|
click: () => send(IPC_COMMANDS.MACHINE_CTRL_ALT_DEL),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Send Alt+F4",
|
label: "Send Alt+F4",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_ALT_F4),
|
click: () => send(IPC_COMMANDS.MACHINE_ALT_F4),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Send Alt+Enter",
|
label: "Send Alt+Enter",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_ALT_ENTER),
|
click: () => send(IPC_COMMANDS.MACHINE_ALT_ENTER),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Send Esc",
|
label: "Send Esc",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_ESC),
|
click: () => send(IPC_COMMANDS.MACHINE_ESC),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
isRunning
|
isRunning
|
||||||
? {
|
? {
|
||||||
label: "Stop",
|
label: "Stop",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_STOP)
|
click: () => send(IPC_COMMANDS.MACHINE_STOP),
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
label: "Start",
|
label: "Start",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_START)
|
click: () => send(IPC_COMMANDS.MACHINE_START),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Restart",
|
label: "Restart",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_RESTART),
|
click: () => send(IPC_COMMANDS.MACHINE_RESTART),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Reset",
|
label: "Reset",
|
||||||
click: () => send(IPC_COMMANDS.MACHINE_RESET),
|
click: () => send(IPC_COMMANDS.MACHINE_RESET),
|
||||||
enabled: isRunning
|
enabled: isRunning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Go to Disk Image",
|
label: "Go to Disk Image",
|
||||||
click: () => send(IPC_COMMANDS.SHOW_DISK_IMAGE)
|
click: () => send(IPC_COMMANDS.SHOW_DISK_IMAGE),
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Help",
|
label: "Help",
|
||||||
|
@ -182,18 +181,18 @@ async function createMenu({ isRunning } = { isRunning: false }) {
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: "Author",
|
label: "Author",
|
||||||
click: () => shell.openExternal(LINKS.homepage)
|
click: () => shell.openExternal(LINKS.homepage),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "windows95 on GitHub",
|
label: "windows95 on GitHub",
|
||||||
click: () => shell.openExternal(LINKS.repo)
|
click: () => shell.openExternal(LINKS.repo),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Help",
|
label: "Help",
|
||||||
click: () => shell.openExternal(LINKS.help)
|
click: () => shell.openExternal(LINKS.help),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Troubleshooting",
|
label: "Troubleshooting",
|
||||||
|
@ -205,12 +204,12 @@ async function createMenu({ isRunning } = { isRunning: false }) {
|
||||||
|
|
||||||
app.relaunch();
|
app.relaunch();
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
|
@ -218,41 +217,41 @@ async function createMenu({ isRunning } = { isRunning: false }) {
|
||||||
label: "windows95",
|
label: "windows95",
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
role: "about"
|
role: "about",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "services"
|
role: "services",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Hide windows95",
|
label: "Hide windows95",
|
||||||
accelerator: "Command+H",
|
accelerator: "Command+H",
|
||||||
role: "hide"
|
role: "hide",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Hide Others",
|
label: "Hide Others",
|
||||||
accelerator: "Command+Shift+H",
|
accelerator: "Command+Shift+H",
|
||||||
role: "hideothers"
|
role: "hideothers",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "unhide"
|
role: "unhide",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "separator"
|
type: "separator",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Quit",
|
label: "Quit",
|
||||||
accelerator: "Command+Q",
|
accelerator: "Command+Q",
|
||||||
click() {
|
click() {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
} as any);
|
} as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ export function setupUpdates() {
|
||||||
if (app.isPackaged) {
|
if (app.isPackaged) {
|
||||||
require("update-electron-app")({
|
require("update-electron-app")({
|
||||||
repo: "felixrieseberg/windows95",
|
repo: "felixrieseberg/windows95",
|
||||||
updateInterval: "1 hour"
|
updateInterval: "1 hour",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ export function getOrCreateWindow(): BrowserWindow {
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
webviewTag: false
|
webviewTag: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.loadFile("./dist/static/index.html");
|
mainWindow.loadFile("./dist/static/index.html");
|
||||||
|
|
|
@ -28,7 +28,7 @@ export class App {
|
||||||
}
|
}
|
||||||
|
|
||||||
window["win95"] = window["win95"] || {
|
window["win95"] = window["win95"] || {
|
||||||
app: new App()
|
app: new App(),
|
||||||
};
|
};
|
||||||
|
|
||||||
window["win95"].app.setup();
|
window["win95"].app.setup();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { shell } from "electron";
|
|
||||||
|
|
||||||
interface CardDriveProps {
|
interface CardDriveProps {
|
||||||
showDiskImage: () => void;
|
showDiskImage: () => void;
|
||||||
|
@ -54,13 +53,8 @@ export class CardDrive extends React.Component<CardDriveProps, CardDriveState> {
|
||||||
<p>
|
<p>
|
||||||
Windows 10 cannot mount raw disk images (ironically, macOS and Linux
|
Windows 10 cannot mount raw disk images (ironically, macOS and Linux
|
||||||
can). However, tools exist that let you mount this drive, like the
|
can). However, tools exist that let you mount this drive, like the
|
||||||
freeware tool{" "}
|
freeware tool <a href="https://google.com">OSFMount</a>. I am not
|
||||||
<a
|
affiliated with it, so please use it at your own risk.
|
||||||
href="https://google.com"
|
|
||||||
>
|
|
||||||
OSFMount
|
|
||||||
</a>
|
|
||||||
. I am not affiliated with it, so please use it at your own risk.
|
|
||||||
</p>
|
</p>
|
||||||
{this.renderMountButton("Windows Explorer")}
|
{this.renderMountButton("Windows Explorer")}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as fs from "fs-extra";
|
import * as fs from "fs-extra";
|
||||||
|
|
||||||
import { CONSTANTS } from "../constants";
|
import { getStatePath } from "./utils/get-state-path";
|
||||||
|
|
||||||
interface CardSettingsProps {
|
interface CardSettingsProps {
|
||||||
bootFromScratch: () => void;
|
bootFromScratch: () => void;
|
||||||
|
@ -24,7 +24,7 @@ export class CardSettings extends React.Component<
|
||||||
this.onResetState = this.onResetState.bind(this);
|
this.onResetState = this.onResetState.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isStateReset: false
|
isStateReset: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,8 +152,10 @@ export class CardSettings extends React.Component<
|
||||||
* Handle the state reset
|
* Handle the state reset
|
||||||
*/
|
*/
|
||||||
private async onResetState() {
|
private async onResetState() {
|
||||||
if (fs.existsSync(CONSTANTS.STATE_PATH)) {
|
const statePath = await getStatePath();
|
||||||
await fs.remove(CONSTANTS.STATE_PATH);
|
|
||||||
|
if (fs.existsSync(statePath)) {
|
||||||
|
await fs.remove(statePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ isStateReset: true });
|
this.setState({ isStateReset: true });
|
||||||
|
|
|
@ -29,7 +29,7 @@ export class EmulatorInfo extends React.Component<
|
||||||
cpu: 0,
|
cpu: 0,
|
||||||
disk: "Idle",
|
disk: "Idle",
|
||||||
lastCounter: 0,
|
lastCounter: 0,
|
||||||
lastTick: 0
|
lastTick: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ export class EmulatorInfo extends React.Component<
|
||||||
this.setState({
|
this.setState({
|
||||||
lastTick: now,
|
lastTick: now,
|
||||||
lastCounter: instructionCounter,
|
lastCounter: instructionCounter,
|
||||||
cpu: Math.round(ips / deltaTime)
|
cpu: Math.round(ips / deltaTime),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as fs from "fs-extra";
|
import * as fs from "fs-extra";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { ipcRenderer, remote, shell } from "electron";
|
import { ipcRenderer, shell } from "electron";
|
||||||
|
|
||||||
import { CONSTANTS, IPC_COMMANDS } from "../constants";
|
import { CONSTANTS, IPC_COMMANDS } from "../constants";
|
||||||
import { getDiskImageSize } from "../utils/disk-image-size";
|
import { getDiskImageSize } from "../utils/disk-image-size";
|
||||||
|
@ -10,6 +10,7 @@ import { StartMenu } from "./start-menu";
|
||||||
import { CardSettings } from "./card-settings";
|
import { CardSettings } from "./card-settings";
|
||||||
import { EmulatorInfo } from "./emulator-info";
|
import { EmulatorInfo } from "./emulator-info";
|
||||||
import { CardDrive } from "./card-drive";
|
import { CardDrive } from "./card-drive";
|
||||||
|
import { getStatePath } from "./utils/get-state-path";
|
||||||
|
|
||||||
export interface EmulatorState {
|
export interface EmulatorState {
|
||||||
currentUiCard: string;
|
currentUiCard: string;
|
||||||
|
@ -41,7 +42,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
isRunning: false,
|
isRunning: false,
|
||||||
currentUiCard: "start",
|
currentUiCard: "start",
|
||||||
isInfoDisplayed: true,
|
isInfoDisplayed: true,
|
||||||
scale: 1
|
scale: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setupInputListeners();
|
this.setupInputListeners();
|
||||||
|
@ -58,7 +59,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
*/
|
*/
|
||||||
public setupInputListeners() {
|
public setupInputListeners() {
|
||||||
// ESC
|
// ESC
|
||||||
document.onkeydown = evt => {
|
document.onkeydown = (evt) => {
|
||||||
const { isCursorCaptured } = this.state;
|
const { isCursorCaptured } = this.state;
|
||||||
|
|
||||||
evt = evt || window.event;
|
evt = evt || window.event;
|
||||||
|
@ -95,11 +96,11 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
this.isQuitting = true;
|
this.isQuitting = true;
|
||||||
|
|
||||||
setImmediate(() => {
|
setImmediate(() => {
|
||||||
remote.app.quit();
|
ipcRenderer.invoke(IPC_COMMANDS.APP_QUIT);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onbeforeunload = event => {
|
window.onbeforeunload = (event: Event) => {
|
||||||
if (this.isQuitting || this.isResetting) {
|
if (this.isQuitting || this.isResetting) {
|
||||||
console.log(`Unload: Not preventing`);
|
console.log(`Unload: Not preventing`);
|
||||||
return;
|
return;
|
||||||
|
@ -122,27 +123,27 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
this.sendKeys([
|
this.sendKeys([
|
||||||
0x1d, // ctrl
|
0x1d, // ctrl
|
||||||
0x38, // alt
|
0x38, // alt
|
||||||
0x53 // delete
|
0x53, // delete
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_F4, () => {
|
ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_F4, () => {
|
||||||
this.sendKeys([
|
this.sendKeys([
|
||||||
0x38, // alt
|
0x38, // alt
|
||||||
0x3e // f4
|
0x3e, // f4
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_ENTER, () => {
|
ipcRenderer.on(IPC_COMMANDS.MACHINE_ALT_ENTER, () => {
|
||||||
this.sendKeys([
|
this.sendKeys([
|
||||||
0x38, // alt
|
0x38, // alt
|
||||||
0 // enter
|
0, // enter
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcRenderer.on(IPC_COMMANDS.MACHINE_ESC, () => {
|
ipcRenderer.on(IPC_COMMANDS.MACHINE_ESC, () => {
|
||||||
this.sendKeys([
|
this.sendKeys([
|
||||||
0x18 // alt
|
0x18, // alt
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -189,7 +190,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
if (currentUiCard === "settings") {
|
if (currentUiCard === "settings") {
|
||||||
card = (
|
card = (
|
||||||
<CardSettings
|
<CardSettings
|
||||||
setFloppy={floppyFile => this.setState({ floppyFile })}
|
setFloppy={(floppyFile) => this.setState({ floppyFile })}
|
||||||
bootFromScratch={this.bootFromScratch}
|
bootFromScratch={this.bootFromScratch}
|
||||||
floppy={floppyFile}
|
floppy={floppyFile}
|
||||||
/>
|
/>
|
||||||
|
@ -204,7 +205,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
<>
|
<>
|
||||||
{card}
|
{card}
|
||||||
<StartMenu
|
<StartMenu
|
||||||
navigate={target => this.setState({ currentUiCard: target })}
|
navigate={(target) => this.setState({ currentUiCard: target })}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -257,10 +258,10 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
*/
|
*/
|
||||||
public showDiskImage() {
|
public showDiskImage() {
|
||||||
// Contents/Resources/app/dist/static
|
// Contents/Resources/app/dist/static
|
||||||
const imagePath = path
|
const imagePath = path.join(__dirname, "../../images/windows95.img");
|
||||||
.join(__dirname, "../../images/windows95.img");
|
|
||||||
|
|
||||||
console.log(`Showing disk image in ${imagePath}`);``
|
console.log(`Showing disk image in ${imagePath}`);
|
||||||
|
``;
|
||||||
|
|
||||||
shell.showItemInFolder(imagePath);
|
shell.showItemInFolder(imagePath);
|
||||||
}
|
}
|
||||||
|
@ -277,20 +278,20 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
video_memory_size: 32 * 1024 * 1024,
|
video_memory_size: 32 * 1024 * 1024,
|
||||||
screen_container: document.getElementById("emulator"),
|
screen_container: document.getElementById("emulator"),
|
||||||
bios: {
|
bios: {
|
||||||
url: "../../bios/seabios.bin"
|
url: "../../bios/seabios.bin",
|
||||||
},
|
},
|
||||||
vga_bios: {
|
vga_bios: {
|
||||||
url: "../../bios/vgabios.bin"
|
url: "../../bios/vgabios.bin",
|
||||||
},
|
},
|
||||||
hda: {
|
hda: {
|
||||||
url: "../../images/windows95.img",
|
url: "../../images/windows95.img",
|
||||||
async: true,
|
async: true,
|
||||||
size: imageSize
|
size: imageSize,
|
||||||
},
|
},
|
||||||
fda: {
|
fda: {
|
||||||
buffer: this.state.floppyFile
|
buffer: this.state.floppyFile,
|
||||||
},
|
},
|
||||||
boot_order: 0x132
|
boot_order: 0x132,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`🚜 Starting emulator with options`, options);
|
console.log(`🚜 Starting emulator with options`, options);
|
||||||
|
@ -300,7 +301,7 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
// New v86 instance
|
// New v86 instance
|
||||||
this.setState({
|
this.setState({
|
||||||
emulator: window["emulator"],
|
emulator: window["emulator"],
|
||||||
isRunning: true
|
isRunning: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcRenderer.send(IPC_COMMANDS.MACHINE_STARTED);
|
ipcRenderer.send(IPC_COMMANDS.MACHINE_STARTED);
|
||||||
|
@ -366,8 +367,9 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
*/
|
*/
|
||||||
private async saveState(): Promise<void> {
|
private async saveState(): Promise<void> {
|
||||||
const { emulator } = this.state;
|
const { emulator } = this.state;
|
||||||
|
const statePath = await getStatePath();
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
if (!emulator || !emulator.save_state) {
|
if (!emulator || !emulator.save_state) {
|
||||||
console.log(`restoreState: No emulator present`);
|
console.log(`restoreState: No emulator present`);
|
||||||
return resolve();
|
return resolve();
|
||||||
|
@ -379,9 +381,9 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.outputFile(CONSTANTS.STATE_PATH, Buffer.from(newState));
|
await fs.outputFile(statePath, Buffer.from(newState));
|
||||||
|
|
||||||
console.log(`saveState: Saved state to ${CONSTANTS.STATE_PATH}`);
|
console.log(`saveState: Saved state to ${statePath}`);
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -391,9 +393,9 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
/**
|
/**
|
||||||
* Restores state to the emulator.
|
* Restores state to the emulator.
|
||||||
*/
|
*/
|
||||||
private restoreState() {
|
private async restoreState() {
|
||||||
const { emulator } = this.state;
|
const { emulator } = this.state;
|
||||||
const state = this.getState();
|
const state = await this.getState();
|
||||||
|
|
||||||
// Nothing to do with if we don't have a state
|
// Nothing to do with if we don't have a state
|
||||||
if (!state) {
|
if (!state) {
|
||||||
|
@ -420,9 +422,10 @@ export class Emulator extends React.Component<{}, EmulatorState> {
|
||||||
*
|
*
|
||||||
* @returns {ArrayBuffer}
|
* @returns {ArrayBuffer}
|
||||||
*/
|
*/
|
||||||
private getState(): ArrayBuffer | null {
|
private async getState(): Promise<ArrayBuffer | null> {
|
||||||
const statePath = fs.existsSync(CONSTANTS.STATE_PATH)
|
const expectedStatePath = await getStatePath();
|
||||||
? CONSTANTS.STATE_PATH
|
const statePath = fs.existsSync(expectedStatePath)
|
||||||
|
? expectedStatePath
|
||||||
: CONSTANTS.DEFAULT_STATE_PATH;
|
: CONSTANTS.DEFAULT_STATE_PATH;
|
||||||
|
|
||||||
if (fs.existsSync(statePath)) {
|
if (fs.existsSync(statePath)) {
|
||||||
|
|
13
src/renderer/utils/get-state-path.ts
Normal file
13
src/renderer/utils/get-state-path.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { ipcRenderer } from "electron";
|
||||||
|
import { IPC_COMMANDS } from "../../constants";
|
||||||
|
|
||||||
|
let _statePath = "";
|
||||||
|
|
||||||
|
export async function getStatePath(): Promise<string> {
|
||||||
|
if (_statePath) {
|
||||||
|
return _statePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statePath = await ipcRenderer.invoke(IPC_COMMANDS.GET_STATE_PATH);
|
||||||
|
return (_statePath = statePath);
|
||||||
|
}
|
23
tools/add-macos-cert.sh
Normal file
23
tools/add-macos-cert.sh
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
KEY_CHAIN=build.keychain
|
||||||
|
MACOS_CERT_P12_FILE=certificate.p12
|
||||||
|
|
||||||
|
# Recreate the certificate from the secure environment variable
|
||||||
|
echo $MACOS_CERT_P12 | base64 --decode > $MACOS_CERT_P12_FILE
|
||||||
|
|
||||||
|
#create a keychain
|
||||||
|
security create-keychain -p actions $KEY_CHAIN
|
||||||
|
|
||||||
|
# Make the keychain the default so identities are found
|
||||||
|
security default-keychain -s $KEY_CHAIN
|
||||||
|
|
||||||
|
# Unlock the keychain
|
||||||
|
security unlock-keychain -p actions $KEY_CHAIN
|
||||||
|
|
||||||
|
security import $MACOS_CERT_P12_FILE -k $KEY_CHAIN -P $MACOS_CERT_PASSWORD -T /usr/bin/codesign;
|
||||||
|
|
||||||
|
security set-key-partition-list -S apple-tool:,apple: -s -k actions $KEY_CHAIN
|
||||||
|
|
||||||
|
# remove certs
|
||||||
|
rm -fr *.p12
|
38
tools/check-links.js
Normal file
38
tools/check-links.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
const fs = require('fs/promises')
|
||||||
|
const path = require('path')
|
||||||
|
const fetch = require('node-fetch')
|
||||||
|
|
||||||
|
const LINK_RGX = /(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?/g;
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const readmePath = path.join(__dirname, '../README.md')
|
||||||
|
const readme = await fs.readFile(readmePath, 'utf-8')
|
||||||
|
const links = readme.match(LINK_RGX)
|
||||||
|
let failed = false
|
||||||
|
|
||||||
|
for (const link of links) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(link, { method: 'HEAD' })
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
// If we're inside GitHub's release asset server, we just ran into AWS not allowing
|
||||||
|
// HEAD requests, which is different from a 404.
|
||||||
|
if (!response.url.startsWith('https://github-production-release-asset')) {
|
||||||
|
throw new Error (`HTTP Error Response: ${response.status} ${response.statusText}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ ${link}`);
|
||||||
|
} catch (error) {
|
||||||
|
failed = true
|
||||||
|
|
||||||
|
console.log(`❌ ${link}\n${error}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed) {
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
11
tools/download-disk.ps1
Normal file
11
tools/download-disk.ps1
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
mkdir images
|
||||||
|
cd images
|
||||||
|
|
||||||
|
$wc = New-Object System.Net.WebClient
|
||||||
|
$wc.DownloadFile($env:DISK_URL, "$(Resolve-Path .)\images.zip")
|
||||||
|
|
||||||
|
7z x images.zip -y -aoa
|
||||||
|
Remove-Item images.zip
|
||||||
|
Remove-Item __MACOSX -Recurse -ErrorAction Ignore
|
||||||
|
cd ..
|
||||||
|
Tree ./ /F
|
10
tools/download-disk.sh
Normal file
10
tools/download-disk.sh
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
mkdir -p ./images
|
||||||
|
cd ./images
|
||||||
|
wget -O images.zip $DISK_URL
|
||||||
|
unzip -o images.zip
|
||||||
|
rm images.zip
|
||||||
|
rm -r __MACOSX
|
||||||
|
cd -
|
||||||
|
ls images
|
|
@ -1,30 +0,0 @@
|
||||||
const { notarize } = require('electron-notarize');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const buildOutput = path.resolve(
|
|
||||||
__dirname,
|
|
||||||
'..',
|
|
||||||
'out',
|
|
||||||
'windows95-darwin-x64',
|
|
||||||
'windows95.app'
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = function () {
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
console.log('Not a Mac; skipping notarization');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Notarizing...');
|
|
||||||
|
|
||||||
return notarize({
|
|
||||||
appBundleId: 'com.felixrieseberg.windows95',
|
|
||||||
appPath: buildOutput,
|
|
||||||
appleId: process.env.APPLE_ID,
|
|
||||||
appleIdPassword: process.env.APPLE_ID_PASSWORD,
|
|
||||||
ascProvider: 'LT94ZKYDCJ'
|
|
||||||
}).catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
throw e;
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
Reference in a new issue