Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit 09e6f32

Browse files
authored
Add files via upload
1 parent ce4cb98 commit 09e6f32

23 files changed

Lines changed: 19434 additions & 0 deletions

package-lock.json

Lines changed: 18494 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"name": "pc-auth",
3+
"version": "0.1.0",
4+
"private": true,
5+
"main": "build/electron",
6+
"homepage": "./",
7+
"dependencies": {
8+
"@fortawesome/fontawesome-svg-core": "^6.4.0",
9+
"@fortawesome/react-fontawesome": "^0.2.0",
10+
"@testing-library/jest-dom": "^5.16.5",
11+
"@testing-library/react": "^13.4.0",
12+
"@testing-library/user-event": "^13.5.0",
13+
"bootstrap": "^5.3.0",
14+
"cookie-session": "^2.0.0",
15+
"cors": "^2.8.5",
16+
"react": "^18.2.0",
17+
"react-bootstrap": "^2.8.0",
18+
"react-dom": "^18.2.0",
19+
"react-hook-form": "^7.45.1",
20+
"react-router-dom": "^6.14.0",
21+
"react-scripts": "5.0.1",
22+
"totp-generator": "^0.0.14"
23+
},
24+
"scripts": {
25+
"start": "react-scripts build && electron .",
26+
"build": "react-scripts build && electron-builder build",
27+
"eject": "react-scripts eject"
28+
},
29+
"build": {
30+
"appId": "com.pc.auth",
31+
"files": [
32+
"build/**/*",
33+
"app/**/*",
34+
"package.json"
35+
],
36+
"directories": {
37+
"output": "dist"
38+
},
39+
"win": {
40+
"target": "nsis",
41+
"icon": "public/logo512.png"
42+
}
43+
},
44+
"eslintConfig": {
45+
"extends": [
46+
"react-app",
47+
"react-app/jest"
48+
]
49+
},
50+
"browserslist": {
51+
"production": [
52+
">0.2%",
53+
"not dead",
54+
"not op_mini all"
55+
],
56+
"development": [
57+
"last 1 chrome version",
58+
"last 1 firefox version",
59+
"last 1 safari version"
60+
]
61+
},
62+
"devDependencies": {
63+
"electron": "^25.2.0"
64+
}
65+
}

public/class/Driver.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
const crypto = require('crypto');
2+
const fs = require('fs');
3+
4+
class Driver {
5+
constructor() {
6+
this.password = null;
7+
this.session = false;
8+
}
9+
10+
create( password ) {
11+
this.password = password;
12+
13+
try {
14+
fs.writeFileSync( './containers.encrypted', this.encrypt( JSON.stringify( [] ) ) );
15+
this.session = true;
16+
return true;
17+
} catch {
18+
return false;
19+
}
20+
}
21+
22+
login( password ) {
23+
this.password = password;
24+
if ( this.isPasswordValid() ) {
25+
this.session = true;
26+
return true;
27+
}
28+
return false;
29+
30+
}
31+
32+
isLoggedIn() {
33+
return this.session !== null;
34+
}
35+
36+
containerExist() {
37+
return fs.existsSync( './containers.encrypted' );
38+
}
39+
40+
isPasswordValid() {
41+
try {
42+
this.read();
43+
return true;
44+
} catch {
45+
return false;
46+
}
47+
}
48+
49+
decrypt( data ) {
50+
const decipher = crypto.createDecipher('aes-256-cbc', this.password);
51+
let response = decipher.update(data.toString(), 'hex', 'utf8');
52+
response += decipher.final('utf8');
53+
return response;
54+
}
55+
56+
encrypt( data ) {
57+
const cipher = crypto.createCipher('aes-256-cbc', this.password);
58+
let response = cipher.update(data, 'utf8', 'hex');
59+
response += cipher.final('hex');
60+
return response;
61+
}
62+
63+
read() {
64+
return JSON.parse( this.decrypt( fs.readFileSync( './containers.encrypted' ) ) );
65+
}
66+
67+
write( data ) {
68+
try {
69+
fs.writeFileSync( './containers.encrypted', this.encrypt( JSON.stringify( data ) ) )
70+
return true
71+
} catch {
72+
return false
73+
}
74+
}
75+
}
76+
77+
module.exports = Driver;

public/electron.js

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
// Modules to control application life and create native browser window
2+
const {
3+
app: electronApp,
4+
ipcMain,
5+
BrowserWindow
6+
} = require('electron')
7+
const totp = require('totp-generator');
8+
const {
9+
v4: uuidv4
10+
} = require('uuid');
11+
const fs = require('fs');
12+
const path = require('path');
13+
const Driver = require('./class/Driver.js');
14+
15+
function createWindow() {
16+
const mainWindow = new BrowserWindow({
17+
width: 800,
18+
height: 500,
19+
minHeight: 800,
20+
maxHeight: 800,
21+
minWidth: 500,
22+
maxWidth: 500,
23+
autoHideMenuBar: true,
24+
icon: path.join(__dirname, 'build/logo192.png'),
25+
webPreferences: {
26+
nodeIntegration: true,
27+
contextIsolation: false,
28+
preload: 'build/preload.js'
29+
}
30+
})
31+
32+
mainWindow.loadFile('build/index.html')
33+
}
34+
35+
36+
electronApp.whenReady().then(() => {
37+
createWindow()
38+
electronApp.on('activate', function() {
39+
if (BrowserWindow.getAllWindows().length === 0) createWindow()
40+
})
41+
})
42+
43+
electronApp.on('window-all-closed', function() {
44+
if (process.platform !== 'darwin') electronApp.quit()
45+
})
46+
47+
const driver = new Driver()
48+
49+
ipcMain.on('register', (event, params) => {
50+
const {
51+
password
52+
} = params
53+
54+
if (driver.create( password ))
55+
event.reply('register-response', {
56+
success: true,
57+
message: 'Encrypted container created.'
58+
})
59+
})
60+
61+
ipcMain.on('auth', (event, params) => {
62+
const {
63+
password
64+
} = params
65+
66+
if (driver.login( password ))
67+
event.reply('auth-response', {
68+
success: true,
69+
message: 'The password is valid.'
70+
})
71+
else
72+
event.reply('auth-response', {
73+
success: false,
74+
message: 'The password is invalid.'
75+
})
76+
})
77+
78+
ipcMain.on('container-exist', (event, params) => {
79+
if (driver.containerExist())
80+
event.reply('container-exist-response', {
81+
success: true,
82+
message: 'The container exist.'
83+
})
84+
else
85+
event.reply('container-exist-response', {
86+
success: false,
87+
message: 'The container does not exist.'
88+
})
89+
})
90+
91+
ipcMain.on('reset-container', (event, params) => {
92+
if (driver.containerExist()) {
93+
fs.unlinkSync('./containers.encrypted')
94+
event.reply('reset-container-response', {
95+
success: true,
96+
message: 'The container was deleted.'
97+
})
98+
} else
99+
event.reply('delete-container-response', {
100+
success: false,
101+
message: 'The container does not exist.'
102+
})
103+
})
104+
105+
ipcMain.on('get-authenticators', (event, params) => {
106+
if (!driver.session)
107+
return response.send({
108+
success: false,
109+
message: 'You must authenticate first.'
110+
})
111+
112+
const totps = []
113+
114+
driver.read().map(data => {
115+
totps.push({
116+
uuid: data.uuid,
117+
label: data.label,
118+
user: data.user,
119+
password: data.password
120+
})
121+
})
122+
123+
event.reply('get-authenticators-response', totps)
124+
125+
})
126+
127+
ipcMain.on('add-authenticator', (event, params) => {
128+
if (!driver.session)
129+
return response.send({
130+
success: false,
131+
message: 'You must authenticate first.'
132+
})
133+
134+
const {
135+
labelname,
136+
user,
137+
password,
138+
secret
139+
} = params
140+
141+
const totps = driver.read()
142+
totps.push({
143+
uuid: uuidv4(),
144+
label: labelname,
145+
user: user,
146+
password: password,
147+
secret: secret
148+
})
149+
150+
if (driver.write(totps))
151+
event.reply('add-authenticator-response', {
152+
success: true,
153+
message: 'The TOTP was created.'
154+
})
155+
else
156+
event.reply('add-authenticator-response', {
157+
success: false,
158+
message: 'The TOTP was not created.'
159+
})
160+
})
161+
162+
ipcMain.on('delete-authenticator', (event, params) => {
163+
if (!driver.session)
164+
return response.send({
165+
success: false,
166+
message: 'You must authenticate first.'
167+
})
168+
169+
const { uuid } = params
170+
const totps = driver.read()
171+
172+
const index = totps.findIndex(totp => totp.uuid === uuid)
173+
174+
if (index === -1)
175+
event.reply('delete-authenticator-response', {
176+
success: false,
177+
message: 'The TOTP does not exist.'
178+
})
179+
else
180+
totps.splice(index, 1)
181+
182+
if (driver.write(totps))
183+
event.reply('delete-authenticator-response', {
184+
success: true,
185+
message: 'The TOTP was deleted.'
186+
})
187+
else
188+
event.reply('delete-totp-response', {
189+
success: false,
190+
message: 'The TOTP was not deleted.'
191+
})
192+
})
193+
194+
ipcMain.on('get-authenticator', (event, params) => {
195+
if (!driver.session)
196+
return response.send({
197+
success: false,
198+
message: 'You must authenticate first.'
199+
})
200+
201+
const {
202+
uuid
203+
} = params
204+
const totps = driver.read()
205+
const index = totps.findIndex(totp => totp.uuid === uuid)
206+
207+
if (index === -1)
208+
event.reply('get-authenticator-response', {
209+
success: false,
210+
message: 'The TOTP does not exist.'
211+
})
212+
else
213+
event.reply('get-authenticator-response', {
214+
success: true,
215+
code: totp( totps[index].secret )
216+
})
217+
})

public/favicon.ico

149 KB
Binary file not shown.

public/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="description" content="Web site created using create-react-app" />
8+
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
9+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
10+
<title>PC Auth - TOTP Manager</title>
11+
</head>
12+
<body>
13+
<noscript>You need to enable JavaScript to run this app.</noscript>
14+
<div id="root"></div>
15+
</body>
16+
</html>

public/logo192.png

35.4 KB
Loading

public/logo512.png

219 KB
Loading

0 commit comments

Comments
 (0)