openvibers/openvibe.billing Commits
Billing vhost: quote the Vibes Pay regex locations (#193)
Changes
@@@ -99,12 +99,12 @@ server {}# Vibes Pay's pay sheet charge: the app, item, price and the person's Vibes (docs/vibes-pay.md). A charge id is# vch_ + 26 Crockford characters; anything else stays a 404 at the catch-all below.-- location ~ ^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}$ {++ location ~ "^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}$" {limit_req zone=ovbilling_console burst=20 nodelay;proxy_pass http://127.0.0.1:4600;}# Pay or cancel that charge; both are POSTs with the person's own bearer token.-- location ~ ^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}/(pay|cancel)$ {++ location ~ "^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}/(pay|cancel)$" {limit_req zone=ovbilling_console burst=10 nodelay;proxy_pass http://127.0.0.1:4600;}@@@ -35,10 +35,14 @@ assert.ok(tls.indexOf(fromBalance[0]) < tls.indexOf('location ^~ /api/ { returnconst activity = tls.match(/location = \/api\/me\/activity \{([^}]*)\}/);assert.ok(activity && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(activity[1]) && /limit_req /.test(activity[1]), 'a rate-limited location for /api/me/activity');assert.ok(tls.indexOf(activity[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');--const charge = tls.match(/location ~ \^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\$ \{([^}]*)\}/);++// nginx reads an unquoted "{" in a location regex as the block's start ("unknown directive"): quote any regex with a brace.++for (const m of tls.matchAll(/^\s*location\s+~\*?\s+(\S+)\s+\{/gm)) {++ assert.ok(!/[{}]/.test(m[1]) || /^".*"$/.test(m[1]), `quote the location regex ${m[1]}: nginx -t fails on an unquoted brace`);++}++const charge = tls.match(/location ~ "\^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\$" \{([^}]*)\}/);assert.ok(charge && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(charge[1]) && /limit_req /.test(charge[1]), 'a rate-limited location for GET /api/me/vibes/charges/:id');assert.ok(tls.indexOf(charge[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');--const chargeAct = tls.match(/location ~ \^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\/\(pay\|cancel\)\$ \{([^}]*)\}/);++const chargeAct = tls.match(/location ~ "\^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\/\(pay\|cancel\)\$" \{([^}]*)\}/);assert.ok(chargeAct && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(chargeAct[1]) && /limit_req /.test(chargeAct[1]), 'a rate-limited location for POST pay/cancel');assert.ok(tls.indexOf(chargeAct[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');const credits = tls.match(/location = \/api\/me\/credits \{([^}]*)\}/);
@@ -99,12 +99,12 @@ server {
@@ -99,12 +99,12 @@ server {
}
}
# Vibes Pay's pay sheet charge: the app, item, price and the person's Vibes (docs/vibes-pay.md). A charge id is
# Vibes Pay's pay sheet charge: the app, item, price and the person's Vibes (docs/vibes-pay.md). A charge id is
# vch_ + 26 Crockford characters; anything else stays a 404 at the catch-all below.
# vch_ + 26 Crockford characters; anything else stays a 404 at the catch-all below.
- location ~ ^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}$ {
+ location ~ "^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}$" {
limit_req zone=ovbilling_console burst=20 nodelay;
limit_req zone=ovbilling_console burst=20 nodelay;
proxy_pass http://127.0.0.1:4600;
proxy_pass http://127.0.0.1:4600;
}
}
# Pay or cancel that charge; both are POSTs with the person's own bearer token.
# Pay or cancel that charge; both are POSTs with the person's own bearer token.
- location ~ ^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}/(pay|cancel)$ {
+ location ~ "^/api/me/vibes/charges/vch_[0-9A-HJKMNP-TV-Z]{26}/(pay|cancel)$" {
limit_req zone=ovbilling_console burst=10 nodelay;
limit_req zone=ovbilling_console burst=10 nodelay;
proxy_pass http://127.0.0.1:4600;
proxy_pass http://127.0.0.1:4600;
}
}
@@ -35,10 +35,14 @@ assert.ok(tls.indexOf(fromBalance[0]) < tls.indexOf('location ^~ /api/ { return
@@ -35,10 +35,14 @@ assert.ok(tls.indexOf(fromBalance[0]) < tls.indexOf('location ^~ /api/ { return
const activity = tls.match(/location = \/api\/me\/activity \{([^}]*)\}/);
const activity = tls.match(/location = \/api\/me\/activity \{([^}]*)\}/);
assert.ok(activity && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(activity[1]) && /limit_req /.test(activity[1]), 'a rate-limited location for /api/me/activity');
assert.ok(activity && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(activity[1]) && /limit_req /.test(activity[1]), 'a rate-limited location for /api/me/activity');
assert.ok(tls.indexOf(activity[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');
assert.ok(tls.indexOf(activity[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');
-const charge = tls.match(/location ~ \^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\$ \{([^}]*)\}/);
+// nginx reads an unquoted "{" in a location regex as the block's start ("unknown directive"): quote any regex with a brace.
+for (const m of tls.matchAll(/^\s*location\s+~\*?\s+(\S+)\s+\{/gm)) {
+ assert.ok(!/[{}]/.test(m[1]) || /^".*"$/.test(m[1]), `quote the location regex ${m[1]}: nginx -t fails on an unquoted brace`);
+}
+const charge = tls.match(/location ~ "\^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\$" \{([^}]*)\}/);
assert.ok(charge && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(charge[1]) && /limit_req /.test(charge[1]), 'a rate-limited location for GET /api/me/vibes/charges/:id');
assert.ok(charge && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(charge[1]) && /limit_req /.test(charge[1]), 'a rate-limited location for GET /api/me/vibes/charges/:id');
assert.ok(tls.indexOf(charge[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');
assert.ok(tls.indexOf(charge[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');
-const chargeAct = tls.match(/location ~ \^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\/\(pay\|cancel\)\$ \{([^}]*)\}/);
+const chargeAct = tls.match(/location ~ "\^\/api\/me\/vibes\/charges\/vch_\[0-9A-HJKMNP-TV-Z\]\{26\}\/\(pay\|cancel\)\$" \{([^}]*)\}/);
assert.ok(chargeAct && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(chargeAct[1]) && /limit_req /.test(chargeAct[1]), 'a rate-limited location for POST pay/cancel');
assert.ok(chargeAct && /proxy_pass http:\/\/127\.0\.0\.1:4600;/.test(chargeAct[1]) && /limit_req /.test(chargeAct[1]), 'a rate-limited location for POST pay/cancel');
assert.ok(tls.indexOf(chargeAct[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');
assert.ok(tls.indexOf(chargeAct[0]) < tls.indexOf('location ^~ /api/ { return 404; }'), 'before the /api 404');
const credits = tls.match(/location = \/api\/me\/credits \{([^}]*)\}/);
const credits = tls.match(/location = \/api\/me\/credits \{([^}]*)\}/);