Skip to content

Commit a493a83

Browse files
committed
implement caching for Express client
1 parent f688139 commit a493a83

File tree

5 files changed

+99
-5
lines changed

5 files changed

+99
-5
lines changed

client_common/src/appguard.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import {AppGuardResponse__Output} from './proto/appguard/AppGuardResponse'
77
import {AppGuardTcpConnection} from './proto/appguard/AppGuardTcpConnection'
88
import {AppGuardHttpResponse} from './proto/appguard/AppGuardHttpResponse'
99
import {AppGuardTcpResponse__Output} from "./proto/appguard/AppGuardTcpResponse";
10-
import {APP_ID_FILE, APP_SECRET_FILE, FIREWALL_DEFAULTS_FILE, TOKEN_FILE} from "./auth";
10+
import {APP_ID_FILE, APP_SECRET_FILE, CACHE_FILE, FIREWALL_DEFAULTS_FILE, TOKEN_FILE} from "./auth";
1111
import {AuthorizationRequest} from "./proto/appguard_commands/AuthorizationRequest";
1212
import {ClientMessage} from "./proto/appguard_commands/ClientMessage";
1313
import {ServerMessage__Output} from "./proto/appguard_commands/ServerMessage";
1414
import {FirewallDefaults, FirewallDefaults__Output} from "./proto/appguard_commands/FirewallDefaults";
15+
import {Cache, CacheKey} from "./cache";
16+
import {FirewallPolicy} from "./proto/appguard_commands/FirewallPolicy";
1517

1618
const opts = {includeDirs: [
1719
'node_modules/@nullnet/appguard-express/node_modules/appguard-client-common/proto/',
@@ -186,6 +188,9 @@ export class AppGuardService {
186188
let firewallDefaults: FirewallDefaults = server_msg.setFirewallDefaults;
187189
console.log("Received firewall defaults from server:", firewallDefaults);
188190
fs.writeFileSync(FIREWALL_DEFAULTS_FILE, JSON.stringify(firewallDefaults), {flag: 'w'});
191+
// empty and update cache
192+
let cache = new Cache(firewallDefaults.cache);
193+
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), {flag: 'w'});
189194
}
190195
if (server_msg.deviceDeauthorized) {
191196
// delete saved app secret and app id
@@ -206,9 +211,30 @@ export class AppGuardService {
206211
}, 10000);
207212
});
208213
}
214+
215+
getFromCache(key: CacheKey) : FirewallPolicy | undefined {
216+
let cache = readCache();
217+
return cache.get(key);
218+
}
219+
220+
insertToCache(key: CacheKey, policy: FirewallPolicy) {
221+
let cache = readCache();
222+
cache.insert(key, policy);
223+
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), {flag: 'w'});
224+
}
209225
}
210226

211227
function readFirewallDefaults(): FirewallDefaults {
212228
let text = fs.readFileSync(FIREWALL_DEFAULTS_FILE, 'utf8');
213229
return JSON.parse(text);
214230
}
231+
232+
function readCache(): Cache {
233+
let text = fs.readFileSync(CACHE_FILE, 'utf8');
234+
if (text.trim() === '') {
235+
let firewallDefaults = readFirewallDefaults();
236+
return new Cache(firewallDefaults.cache);
237+
} else {
238+
return JSON.parse(text);
239+
}
240+
}

client_common/src/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export const APP_ID_FILE = process.cwd() + '/../app_id.txt'
88
export const APP_SECRET_FILE = process.cwd() + '/../app_secret.txt'
99
export const FIREWALL_DEFAULTS_FILE = process.cwd() + '/../firewall_defaults.json'
1010
export const UUID_FILE = process.cwd() + '/../uuid.txt'
11+
export const CACHE_FILE = process.cwd() + '/../cache.txt'
1112

1213
const fs = require('fs');
1314

client_common/src/cache.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {FirewallPolicy} from "./proto/appguard_commands/FirewallPolicy";
2+
3+
export class CacheKey {
4+
originalUrl: string;
5+
method: string;
6+
body: string;
7+
sourceIp: string;
8+
headers: Record<string, string>;
9+
query: Record<string, string>;
10+
}
11+
12+
export class Cache {
13+
private active: boolean;
14+
private cache: Map<CacheKey, FirewallPolicy>;
15+
16+
constructor(active: boolean) {
17+
this.active = active;
18+
this.cache = new Map<CacheKey, FirewallPolicy>();
19+
}
20+
21+
get(key: CacheKey): FirewallPolicy | undefined {
22+
if (this.active) {
23+
return this.cache.get(key);
24+
} else {
25+
return undefined;
26+
}
27+
}
28+
29+
insert(key: CacheKey, policy: FirewallPolicy) {
30+
if (this.active) {
31+
this.cache.set(key, policy);
32+
}
33+
}
34+
}

client_common/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export {FirewallPolicy} from "./proto/appguard_commands/FirewallPolicy";
22
export {AppGuardService} from './appguard';
33
export {AuthHandler} from './auth';
4-
export {AppGuardTcpInfo} from './proto/appguard/AppGuardTcpInfo';
4+
export {AppGuardTcpInfo} from './proto/appguard/AppGuardTcpInfo';
5+
export {CacheKey} from './cache';

clients/express/src/express-middleware.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { NextFunction, Request, Response, Send } from 'express';
2-
import { FirewallPolicy, AppGuardTcpInfo, AppGuardService, AuthHandler } from 'appguard-client-common';
2+
import { FirewallPolicy, AppGuardTcpInfo, AppGuardService, AuthHandler, CacheKey } from 'appguard-client-common';
33

44
type ExpressMiddleware = (
55
req: Request,
@@ -21,7 +21,8 @@ export const createAppGuardMiddleware = () => {
2121

2222
const attachResponseHandlers = (
2323
res: Response,
24-
tcp_info: AppGuardTcpInfo
24+
tcp_info: AppGuardTcpInfo,
25+
cacheKey: CacheKey,
2526
) => {
2627
// Storing the original send function
2728
// @ts-ignore
@@ -49,10 +50,12 @@ export const createAppGuardMiddleware = () => {
4950
));
5051

5152
if (handleHTTPResponseResponse.policy === FirewallPolicy.DENY) {
53+
appGuardService.insertToCache(cacheKey, FirewallPolicy.DENY);
5254
// Destroying the socket connection instead of sending the response
5355
// @ts-ignore
5456
res.socket?.destroy();
5557
} else {
58+
appGuardService.insertToCache(cacheKey, FirewallPolicy.ALLOW);
5659
// Intercepting the response.send() call
5760
// Calling the original send function
5861
//@ts-expect-error: This function is this context
@@ -72,6 +75,7 @@ export const createAppGuardMiddleware = () => {
7275
// @ts-ignore
7376
req.socket.remoteAddress;
7477

78+
7579
// console.log(
7680
// // @ts-ignore
7781
// `Appguard Debug XRI:${req.headers['x-real-ip']} - XFF:${req.headers['x-forwarded-for']} TCP/PROXY:${req.socket.remoteAddress} SRC=${sourceIp}`
@@ -82,6 +86,32 @@ export const createAppGuardMiddleware = () => {
8286
// `Appguard Debug From - ${sourceIp} - ${req.method} ${req.originalUrl}`
8387
// );
8488

89+
let cacheKey: CacheKey = {
90+
// @ts-ignore
91+
originalUrl: req.originalUrl,
92+
// @ts-ignore
93+
method: req.method,
94+
// @ts-ignore
95+
body: req.body,
96+
// @ts-ignore
97+
sourceIp: sourceIp,
98+
// @ts-ignore
99+
headers: req.headers as Record<string, string>,
100+
// @ts-ignore
101+
query: req.query as Record<string, string>,
102+
};
103+
104+
let cached = appGuardService.getFromCache(cacheKey);
105+
if (cached !== undefined) {
106+
if (cached === FirewallPolicy.DENY) {
107+
// @ts-ignore
108+
res.socket?.destroy();
109+
} else {
110+
next();
111+
}
112+
return;
113+
}
114+
85115
const handleTCPConnectionResponse = await appGuardService.connectionPromise(
86116
{
87117
// @ts-ignore
@@ -122,6 +152,7 @@ export const createAppGuardMiddleware = () => {
122152

123153
const policy = handleHTTPRequestResponse.policy;
124154
if (policy === FirewallPolicy.DENY) {
155+
appGuardService.insertToCache(cacheKey, FirewallPolicy.DENY);
125156
// Destroying the socket connection instead of sending the response
126157
// @ts-ignore
127158
res.socket?.destroy();
@@ -130,7 +161,8 @@ export const createAppGuardMiddleware = () => {
130161
// attach response handlers after we get the req.id
131162
attachResponseHandlers(
132163
res,
133-
handleTCPConnectionResponse.tcpInfo as AppGuardTcpInfo
164+
handleTCPConnectionResponse.tcpInfo as AppGuardTcpInfo,
165+
cacheKey
134166
);
135167
next();
136168
}

0 commit comments

Comments
 (0)