create-dacosta-proj 1.0.14 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-dacosta-proj",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "bin": {
5
5
  "create-dacosta-proj": "./index.js"
6
6
  }
@@ -7,16 +7,8 @@ PROJECT_WEB_PORT=
7
7
 
8
8
  # Supabase
9
9
 
10
- SUPABASE_PROJECT_URL=
11
- SUPABASE_SECRET_KEY=
12
-
13
- # API
14
-
15
- API_PORT=
16
- API_BYPASS_TOKEN=
10
+ SUPABASE_PROJECT_URL_DEV=
11
+ SUPABASE_SECRET_KEY_DEV=
17
12
 
18
- # Encryption
19
-
20
- ENCRYPTION_KEY=
21
- SIGNATURE_KEY=
22
- SIGNATURE_REF=
13
+ SUPABASE_PROJECT_URL=
14
+ SUPABASE_SECRET_KEY=
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
+ "ignoreDeprecations": "6.0",
3
4
  "baseUrl": ".",
4
5
  "paths": {
5
6
  "@/*": ["src/*"]
@@ -8,15 +8,11 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "cors": "^2.8.6",
11
- "cryptr": "^6.4.0",
12
11
  "dotenv": "^17.3.1",
13
- "express": "^5.2.1",
14
12
  "module-alias": "^2.3.4",
15
13
  "nanoid": "^5.1.6",
16
- "rate-limiter-flexible": "^9.1.1",
17
14
  "redis": "^5.11.0",
18
- "simple-supabase": "^2.0.5",
19
- "zod": "^4.3.6"
15
+ "simple-supabase": "^2.0.10"
20
16
  },
21
17
  "devDependencies": {
22
18
  "eslint": "^9.39.3",
@@ -2,13 +2,11 @@
2
2
  * @type {{
3
3
  * db: import('simple-supabase').DB | null,
4
4
  * redis: import('redis').RedisClientType | null,
5
- * cryptr: import('cryptr'),
6
5
  * }}
7
6
  */
8
7
 
9
8
  const global = {
10
9
  db: null,
11
10
  redis: null,
12
- cryptr: null,
13
11
  };
14
12
  module.exports = { global };
@@ -5,10 +5,10 @@ require('module-alias/register');
5
5
 
6
6
  // Packages / Helpers
7
7
 
8
+ const dev = require('@/../devref.json');
8
9
  const { global } = require('@/config/global');
9
10
  const { SimpleSupabase } = require('simple-supabase');
10
11
  const { createClient: createRedisClient } = require('redis');
11
- const Cryptr = require('cryptr');
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
14
 
@@ -26,11 +26,11 @@ const path = require('path');
26
26
 
27
27
  // Database / Redis
28
28
 
29
+ const projectUrl = process.env[`SUPABASE_PROJECT_URL${dev ? '_DEV' : ''}`]
30
+ const serviceKey = process.env[`SUPABASE_SECRET_KEY${dev ? '_DEV' : ''}`]
31
+
29
32
  let db = await SimpleSupabase({
30
- credentials: {
31
- projectUrl: process.env.SUPABASE_PROJECT_URL,
32
- serviceKey: process.env.SUPABASE_SECRET_KEY
33
- },
33
+ credentials: { projectUrl, serviceKey },
34
34
  redisPrefix: process.env.PROJECT_ID
35
35
  });
36
36
 
@@ -43,12 +43,6 @@ const path = require('path');
43
43
 
44
44
  global.redis = redis;
45
45
 
46
- // Cryptr
47
-
48
- const cryptr = new Cryptr(process.env.ENCRYPTION_KEY);
49
-
50
- global.cryptr = cryptr;
51
-
52
46
  // Start Services
53
47
 
54
48
  fs.readdirSync(path.join(__dirname, 'services'))
@@ -1,45 +0,0 @@
1
- // Packages / Helpers
2
-
3
- const crypto = require('crypto');
4
- const { global } = require('@/config/global');
5
- const { default: zod } = require('zod');
6
-
7
- async function GET({ headers }) {
8
-
9
- try {
10
- // Get Details
11
-
12
- const userId = headers['user-id'];
13
- const accessToken = headers['access-token'];
14
-
15
- // Format Signature
16
-
17
- const expires = Date.now() + (1_000 * 60 * 60 * 1); // 1 Hour
18
-
19
- const hmac = crypto.createHmac('sha256', process.env.SIGNATURE_KEY)
20
- .update(`${userId}:${accessToken}:${expires}:${process.env.SIGNATURE_REF}`)
21
- .digest('hex');
22
-
23
- const signature = global.cryptr.encrypt(`${expires}.${hmac}`);
24
-
25
- return {
26
- code: 200,
27
- json: { signature }
28
- };
29
- }
30
- catch (err) { console.log('Signature Generation Failed', err); return { code: 500, json: { error: 'Failed to generate signature!' } }; }
31
- }
32
-
33
- module.exports = {
34
- GET,
35
- settings: {
36
- requires_bypass: true
37
- },
38
- schemas: {
39
- headers: zod.object({
40
- 'user-id': zod.string(),
41
- 'access-token': zod.string(),
42
- 'bypass': zod.string()
43
- })
44
- }
45
- };
@@ -1,4 +0,0 @@
1
- const config = {
2
- api_version: 1
3
- };
4
- module.exports = { config };
@@ -1,28 +0,0 @@
1
- const crypto = require('crypto');
2
- const { global } = require('@/config/global');
3
-
4
- module.exports = (signature, userId, accessToken) => {
5
-
6
- try {
7
- signature = global.cryptr.decrypt(signature);
8
-
9
- const parts = signature.split('.');
10
- if (parts.length !== 2) return false;
11
- const [sigExpires, sigHmac] = parts;
12
-
13
- if (Date.now() > Number(sigExpires)) return false;
14
-
15
- const expectedHmac = crypto.createHmac('sha256', process.env.SIGNATURE_KEY)
16
- .update(`${userId}:${accessToken}:${sigExpires}:${process.env.SIGNATURE_REF}`)
17
- .digest('hex');
18
-
19
- const isValid = crypto.timingSafeEqual(
20
- Uint8Array.from([...sigHmac].map(c => c.charCodeAt(0))),
21
- Uint8Array.from([...expectedHmac].map(c => c.charCodeAt(0)))
22
- );
23
- if (!isValid) return false;
24
-
25
- return true;
26
- }
27
- catch (err) { console.log('Signature Verification Failed', err); return false; }
28
- };
@@ -1,160 +0,0 @@
1
- // Packages / Helpers
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const express = require('express');
6
- const cors = require('cors');
7
- const { RateLimiterRedis } = require('rate-limiter-flexible');
8
- const verifySignature = require('@/helpers/verifySignature');
9
- const { global } = require('@/config/global');
10
- const { config } = require('@/config/config');
11
-
12
- module.exports = async () => {
13
-
14
- // Start API
15
-
16
- const api = express();
17
- api.use(express.urlencoded({ limit: '10mb', extended: true }));
18
- api.use(express.json({ limit: '10mb' }));
19
-
20
- const allowedOrigins = [
21
- `https://${process.env.PROJECT_WEB_DOMAIN}`,
22
- `http://localhost:${process.env.PROJECT_WEB_PORT}`
23
- ];
24
-
25
- api.use(cors({
26
- origin: (origin, callback) => {
27
- if (!origin || allowedOrigins.includes(origin)) return callback(null, true);
28
- return callback(new Error('Not allowed by CORS'));
29
- }
30
- }));
31
-
32
- // Get Endpoints
33
-
34
- const endpoints = fs.readdirSync(path.join(__dirname, '..', 'api'), { recursive: true })
35
- .filter(f => f.endsWith('.js') && !f.startsWith('_'))
36
- .map(endpoint => endpoint.replace('.js', ''));
37
-
38
- const slashEndpoints = endpoints.map(e => `/${e}`);
39
-
40
- // Endpoint Data
41
-
42
- let endpointRateLimiter = {};
43
- let endpointSettings = {};
44
- let endpointSchemas = {};
45
-
46
- endpoints.forEach(endpoint => {
47
- try {
48
- const data = require(`@/api/${endpoint}`);
49
- endpointRateLimiter[`/${endpoint}`] = new RateLimiterRedis({
50
- storeClient: global.redis,
51
- keyPrefix: `${process.env.PROJECT_ID}_request_rate_limit_${endpoint}`,
52
- ...(data?.rate_limit || { points: 1, duration: 2 }),
53
- useRedisPackage: true
54
- });
55
- endpointSettings[`/${endpoint}`] = data?.settings || {};
56
- endpointSchemas[`/${endpoint}`] = data?.schemas || {};
57
- }
58
- catch (err) {
59
- console.log('API Endpoint Data Listing Error', `Endpoint: ${endpoint}`, err);
60
- endpointSettings[`/${endpoint}`] = {};
61
- endpointSchemas[`/${endpoint}`] = {};
62
- }
63
- });
64
-
65
- // API Authentication
66
-
67
- api.use('/', async (req, res, next) => {
68
-
69
- // Get Endpoint Data
70
-
71
- const endpoint = req?.path || '';
72
- const rateLimiter = endpointRateLimiter[endpoint];
73
- const settings = endpointSettings[endpoint];
74
- const schemas = endpointSchemas[endpoint];
75
-
76
- // Check Endpoint
77
-
78
- if (!slashEndpoints.includes(endpoint)) return res.sendStatus(404);
79
-
80
- // Check Schemas
81
-
82
- const invalidSchema = ['query','headers','body']
83
- .filter(schema => schemas[schema])
84
- .map(schema => {
85
- return { id: schema, parsed: schemas[schema].safeParse(req[schema] || {}) };
86
- })
87
- .find(schema => !schema?.parsed?.success);
88
-
89
- if (invalidSchema?.id) return res.status(400).json({ error: 'Missing params!' });
90
-
91
- // Check Bypass
92
-
93
- if (settings?.requires_bypass) {
94
- const bypass = req.headers['bypass'];
95
- if (bypass !== process.env.API_BYPASS_TOKEN) return res.sendStatus(401);
96
- }
97
-
98
- // Public Endpoint
99
-
100
- if (endpoint.includes(`/v${config.api_version}/public`)) return next();
101
-
102
- // Private Endpoint
103
-
104
- try {
105
- // Get Request Details
106
-
107
- const userId = req.headers['user-id'];
108
- const accessToken = req.headers['access-token'];
109
- const signature = req.headers['signature'];
110
-
111
- if (!userId || !accessToken || !signature) return res.sendStatus(401);
112
-
113
- // Check Rate Limit
114
-
115
- try { await rateLimiter.consume(userId, 1); }
116
- catch (err) { return res.status(429).json({ error: 'Too many requests!', resets_at: new Date(Date.now() + (err?.msBeforeNext || 0)).toISOString() }); }
117
-
118
- // Verify Signature
119
-
120
- const signatureIsValid = verifySignature(signature, userId, accessToken);
121
- if (!signatureIsValid) return res.sendStatus(401);
122
-
123
- // Verify User
124
-
125
- // TODO: Create user verification logic!
126
-
127
- // Return
128
-
129
- return next();
130
- }
131
- catch (err) { console.log('API Middleware Error', `Endpoint: ${endpoint}`, err); return res.sendStatus(500); }
132
- });
133
-
134
- // Start API Endpoints
135
-
136
- endpoints.forEach(endpoint => {
137
-
138
- let endpointMethods = require(`@/api/${endpoint}`);
139
-
140
- api.all(`/${endpoint}`, async (req, res) => {
141
-
142
- const method = endpointMethods[(req?.method || 'GET').toUpperCase()];
143
- if (!method) return res.sendStatus(405);
144
-
145
- try {
146
- const result = await method({ userId: req.headers['user-id'], req, res, endpoint, headers: req.headers || {}, body: req?.body || {}, query: req?.query || {} });
147
- return res.status(result?.code || 200).json(result?.json || {});
148
- }
149
- catch (err) {
150
- console.log('API Error', `Endpoint: ${endpoint}`, err);
151
- try { return res.sendStatus(500); }
152
- catch {}
153
- }
154
- });
155
- });
156
-
157
- // Listen
158
-
159
- api.listen(Number(process.env.API_PORT), () => console.log(`[API] Running on port ${process.env.API_PORT}`));
160
- };