Skip to content

Commit 0d1c93b

Browse files
authored
Pre-0.7.0 fixes (#73)
* Tighten permissions on HPKE keys * Add "burndown-enabled" to /api/info * Fix burndown/revoke nits * Loop on decremented variable * Boyscouting * Fix actor/hostname handling * TOTP is required for BurnDown * Don't interpolate SQL strings TIL you can parameterize OFFSET and LIMIT and it... just works. * Enforce BurnDown * Cap penalty to 2^60 times the base penalty * Prevent locking race conditions * Throw on error * Fix BurnDown tests * Specification compliance nit Now the correct array indices are used * Use hash_equals() here It isn't a security impact, but might as well be consistent * Remove dead constant * Rate-limit filesystem backend: use exclusive locks * Throw on NULL hostnames * Update test * Regenerate Reference Docs * Fix sqlite * Add missing annotation * Do we need to clear the transactions? * Proposed fix * More rollbacks * More retries * Force rollback * Fix timeouts * Regenerate docs * Use different test domain * Lock for shorter intervals * END TRANSACTION in finally block * Nits * Attempted fix: correct PRAGMA usage * Remove kludge
1 parent de4bce3 commit 0d1c93b

39 files changed

Lines changed: 224 additions & 84 deletions

autoload-phpunit.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,17 @@ function tableExists(EasyDB $db, string $tableName): bool
5959
mkdir(__DIR__ . '/tmp/db/', 0777, true);
6060
}
6161
$temp = __DIR__ . '/tmp/db/' . sodium_bin2hex(random_bytes(16)) . '-test.db';
62-
$pkdConfig->withDatabase(new EasyDBCache(new PDO('sqlite:' . $temp)));
62+
$mainPDO = new PDO('sqlite:' . $temp);
63+
$mainPDO->exec('PRAGMA jounral_mode=WAL');
64+
$mainPDO->exec('PRAGMA busy_timeout=5000');
65+
$pkdConfig->withDatabase(new EasyDBCache($mainPDO));
6366
chmod($temp, 0777);
6467

6568
// Create second DB connection for testing concurrency
66-
$GLOBALS['PKD_PHPUNIT_DB'] = new EasyDBCache(new PDO('sqlite:' . $temp));
69+
$secondPDO = new PDO('sqlite:' . $temp);
70+
$secondPDO->exec('PRAGMA jounral_mode=WAL');
71+
$secondPDO->exec('PRAGMA busy_timeout=5000');
72+
$GLOBALS['PKD_PHPUNIT_DB'] = new EasyDBCache($secondPDO);
6773

6874
// Call cleanup-test-db.php to cleanup test file after phpunit is finished.
6975
if (getenv('AUTO_CLEANUP_TEST_DB')) {

config/hpke.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,6 @@
4949
'encaps-key' =>
5050
Base64UrlSafe::encodeUnpadded($encapsKey->bytes),
5151
], JSON_PRETTY_PRINT));
52+
chmod(__DIR__ . '/hpke.json', 0600);
5253
}
5354
return new HPKE($hpke, $decapsKey, $encapsKey);

docs/reference/classes/meta.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ Server configuration parameters
2828
| `$hostname` | `string` | (readonly) |
2929
| `$cacheKey` | `string` | (readonly) |
3030
| `$httpCacheTtl` | `int` | (readonly) |
31+
| `$serverAllowsBurnDown` | `bool` | (readonly) |
3132

3233
### Methods
3334

34-
#### [`__construct`](../../../src/Meta/Params.php#L19-L45)
35+
#### [`__construct`](../../../src/Meta/Params.php#L19-L46)
3536

3637
Returns `void`
3738

@@ -45,34 +46,39 @@ These parameters MUST be public and MUST have a default value
4546
- `$hostname`: `string` = 'localhost'
4647
- `$cacheKey`: `string` = ''
4748
- `$httpCacheTtl`: `int` = 60
49+
- `$serverAllowsBurnDown`: `bool` = true
4850

4951
**Throws:** `DependencyException`
5052

51-
#### [`getActorUsername`](../../../src/Meta/Params.php#L47-L50)
53+
#### [`getActorUsername`](../../../src/Meta/Params.php#L48-L51)
5254

5355
Returns `string`
5456

55-
#### [`getCacheKey`](../../../src/Meta/Params.php#L52-L55)
57+
#### [`getBurnDownEnabled`](../../../src/Meta/Params.php#L53-L56)
58+
59+
Returns `bool`
60+
61+
#### [`getCacheKey`](../../../src/Meta/Params.php#L58-L61)
5662

5763
Returns `string`
5864

59-
#### [`getHashFunction`](../../../src/Meta/Params.php#L57-L60)
65+
#### [`getHashFunction`](../../../src/Meta/Params.php#L63-L66)
6066

6167
Returns `string`
6268

63-
#### [`getHostname`](../../../src/Meta/Params.php#L62-L65)
69+
#### [`getHostname`](../../../src/Meta/Params.php#L68-L71)
6470

6571
Returns `string`
6672

67-
#### [`getHttpCacheTtl`](../../../src/Meta/Params.php#L67-L70)
73+
#### [`getHttpCacheTtl`](../../../src/Meta/Params.php#L73-L76)
6874

6975
Returns `int`
7076

71-
#### [`getOtpMaxLife`](../../../src/Meta/Params.php#L72-L75)
77+
#### [`getOtpMaxLife`](../../../src/Meta/Params.php#L78-L81)
7278

7379
Returns `int`
7480

75-
#### [`getEmptyTreeRoot`](../../../src/Meta/Params.php#L77-L80)
81+
#### [`getEmptyTreeRoot`](../../../src/Meta/Params.php#L83-L86)
7682

7783
Returns `string`
7884

docs/reference/classes/ratelimit.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ Returns `?DateTimeImmutable`
142142

143143
**Throws:** `DateMalformedIntervalStringException`
144144

145-
#### [`getIntervalFromFailureCount`](../../../src/RateLimit/DefaultRateLimiting.php#L249-L262)
145+
#### [`getIntervalFromFailureCount`](../../../src/RateLimit/DefaultRateLimiting.php#L249-L263)
146146

147147
Returns `DateInterval`
148148

@@ -152,7 +152,7 @@ Returns `DateInterval`
152152

153153
**Throws:** `DateMalformedIntervalStringException`
154154

155-
#### [`recordPenalty`](../../../src/RateLimit/DefaultRateLimiting.php#L268-L277)
155+
#### [`recordPenalty`](../../../src/RateLimit/DefaultRateLimiting.php#L269-L278)
156156

157157
Returns `void`
158158

@@ -165,7 +165,7 @@ Returns `void`
165165

166166
**Throws:** `DateMalformedIntervalStringException`
167167

168-
#### [`increaseFailures`](../../../src/RateLimit/DefaultRateLimiting.php#L282-L296)
168+
#### [`increaseFailures`](../../../src/RateLimit/DefaultRateLimiting.php#L283-L297)
169169

170170
Returns `FediE2EE\PKDServer\RateLimit\RateLimitData`
171171

@@ -235,15 +235,15 @@ Returns `string`
235235

236236
- `$array`: `array`
237237

238-
#### [`getRequestActor`](../../../src/RateLimit/DefaultRateLimiting.php#L155-L175)
238+
#### [`getRequestActor`](../../../src/RateLimit/DefaultRateLimiting.php#L155-L173)
239239

240240
Returns `?string`
241241

242242
**Parameters:**
243243

244244
- `$request`: `Psr\Http\Message\ServerRequestInterface`
245245

246-
#### [`getRequestDomain`](../../../src/RateLimit/DefaultRateLimiting.php#L177-L185)
246+
#### [`getRequestDomain`](../../../src/RateLimit/DefaultRateLimiting.php#L175-L183)
247247

248248
Returns `?string`
249249

docs/reference/classes/requesthandlers-api.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,13 +320,13 @@ static · Returns `string`
320320

321321
### Methods
322322

323-
#### [`__construct`](../../../src/RequestHandlers/Api/BurnDown.php#L49-L52)
323+
#### [`__construct`](../../../src/RequestHandlers/Api/BurnDown.php#L54-L57)
324324

325325
Returns `void`
326326

327327
**Throws:** `DependencyException`
328328

329-
#### [`handle`](../../../src/RequestHandlers/Api/BurnDown.php#L69-L91)
329+
#### [`handle`](../../../src/RequestHandlers/Api/BurnDown.php#L79-L106)
330330

331331
Returns `Psr\Http\Message\ResponseInterface`
332332

@@ -336,7 +336,7 @@ Returns `Psr\Http\Message\ResponseInterface`
336336

337337
- `$request`: `Psr\Http\Message\ServerRequestInterface`
338338

339-
**Throws:** `CacheException`, `CertaintyException`, `CryptoException`, `DependencyException`, `HPKEException`, `JsonException`, `NotImplementedException`, `ParserException`, `SodiumException`, `TableException`, `InvalidArgumentException`
339+
**Throws:** `BaseJsonException`, `BundleException`, `CacheException`, `CertaintyException`, `ConcurrentException`, `CryptoException`, `DateMalformedStringException`, `DependencyException`, `HPKEException`, `InvalidArgumentException`, `JsonException`, `NotImplementedException`, `ParserException`, `RandomException`, `SodiumException`, `TableException`
340340

341341
#### [`getVerifiedStream`](../../../src/RequestHandlers/Api/BurnDown.php#L39-L62)
342342

@@ -2707,7 +2707,7 @@ static · Returns `string`
27072707

27082708
### Methods
27092709

2710-
#### [`handle`](../../../src/RequestHandlers/Api/Info.php#L34-L45)
2710+
#### [`handle`](../../../src/RequestHandlers/Api/Info.php#L34-L46)
27112711

27122712
Returns `Psr\Http\Message\ResponseInterface`
27132713

docs/reference/classes/tables.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ Return the witness data (including public key) for a given origin
342342

343343
**Throws:** `TableException`
344344

345-
#### [`addWitnessCosignature`](../../../src/Tables/MerkleState.php#L112-L157)
345+
#### [`addWitnessCosignature`](../../../src/Tables/MerkleState.php#L112-L160)
346346

347347
**API** · Returns `bool`
348348

@@ -354,29 +354,29 @@ Return the witness data (including public key) for a given origin
354354

355355
**Throws:** `CryptoException`, `DependencyException`, `JsonException`, `NotImplementedException`, `ProtocolException`, `SodiumException`, `TableException`
356356

357-
#### [`getCosignatures`](../../../src/Tables/MerkleState.php#L162-L180)
357+
#### [`getCosignatures`](../../../src/Tables/MerkleState.php#L165-L183)
358358

359359
Returns `array`
360360

361361
**Parameters:**
362362

363363
- `$leafId`: `int`
364364

365-
#### [`countCosignatures`](../../../src/Tables/MerkleState.php#L182-L192)
365+
#### [`countCosignatures`](../../../src/Tables/MerkleState.php#L185-L195)
366366

367367
Returns `int`
368368

369369
**Parameters:**
370370

371371
- `$leafId`: `int`
372372

373-
#### [`getLatestRoot`](../../../src/Tables/MerkleState.php#L200-L209)
373+
#### [`getLatestRoot`](../../../src/Tables/MerkleState.php#L203-L212)
374374

375375
**API** · Returns `string`
376376

377377
**Throws:** `DependencyException`, `SodiumException`
378378

379-
#### [`insertLeaf`](../../../src/Tables/MerkleState.php#L228-L292)
379+
#### [`insertLeaf`](../../../src/Tables/MerkleState.php#L231-L295)
380380

381381
**API** · Returns `bool`
382382

@@ -386,27 +386,27 @@ Insert leaf with retry logic for deadlocks
386386

387387
- `$leaf`: `FediE2EE\PKDServer\Tables\Records\MerkleLeaf`
388388
- `$inTransaction`: `callable`
389-
- `$maxRetries`: `int` = 5
389+
- `$maxRetries`: `int` = 20
390390

391391
**Throws:** `ConcurrentException`, `CryptoException`, `DependencyException`, `NotImplementedException`, `RandomException`, `SodiumException`
392392

393-
#### [`getLeafByRoot`](../../../src/Tables/MerkleState.php#L311-L327)
393+
#### [`getLeafByRoot`](../../../src/Tables/MerkleState.php#L314-L330)
394394

395395
**API** · Returns `?FediE2EE\PKDServer\Tables\Records\MerkleLeaf`
396396

397397
**Parameters:**
398398

399399
- `$root`: `string`
400400

401-
#### [`getLeafByID`](../../../src/Tables/MerkleState.php#L332-L348)
401+
#### [`getLeafByID`](../../../src/Tables/MerkleState.php#L335-L351)
402402

403403
**API** · Returns `?FediE2EE\PKDServer\Tables\Records\MerkleLeaf`
404404

405405
**Parameters:**
406406

407407
- `$primaryKey`: `int`
408408

409-
#### [`getHashesSince`](../../../src/Tables/MerkleState.php#L388-L430)
409+
#### [`getHashesSince`](../../../src/Tables/MerkleState.php#L391-L435)
410410

411411
**API** · Returns `array`
412412

@@ -994,7 +994,7 @@ Returns `void`
994994

995995
**Throws:** `JsonException`, `TableException`
996996

997-
#### [`getHistory`](../../../src/Tables/ReplicaHistory.php#L71-L82)
997+
#### [`getHistory`](../../../src/Tables/ReplicaHistory.php#L71-L84)
998998

999999
Returns `array`
10001000

@@ -1006,7 +1006,7 @@ Returns `array`
10061006

10071007
**Throws:** `JsonException`
10081008

1009-
#### [`getHistorySince`](../../../src/Tables/ReplicaHistory.php#L88-L108)
1009+
#### [`getHistorySince`](../../../src/Tables/ReplicaHistory.php#L90-L110)
10101010

10111011
Returns `array`
10121012

docs/reference/classes/traits.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -873,15 +873,15 @@ Returns `string`
873873

874874
- `$array`: `array`
875875

876-
#### [`getRequestActor`](../../../src/Traits/NetworkTrait.php#L155-L175)
876+
#### [`getRequestActor`](../../../src/Traits/NetworkTrait.php#L155-L173)
877877

878878
Returns `?string`
879879

880880
**Parameters:**
881881

882882
- `$request`: `Psr\Http\Message\ServerRequestInterface`
883883

884-
#### [`getRequestDomain`](../../../src/Traits/NetworkTrait.php#L177-L185)
884+
#### [`getRequestDomain`](../../../src/Traits/NetworkTrait.php#L175-L183)
885885

886886
Returns `?string`
887887

docs/reference/routes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ This document lists all API routes defined via `#[Route]` attributes.
88
|---------------|---------------|--------|
99
| `/` | [`RequestHandlers\IndexPage`](../../src/RequestHandlers/IndexPage.php) | `handle` |
1010
| `/.well-known/webfinger` | [`RequestHandlers\ActivityPub\Finger`](../../src/RequestHandlers/ActivityPub/Finger.php) | `handle` |
11-
| `/api/burndown` | [`RequestHandlers\Api\Revoke`](../../src/RequestHandlers/Api/Revoke.php) | `handle` |
11+
| `/api/burndown` | [`RequestHandlers\Api\BurnDown`](../../src/RequestHandlers/Api/BurnDown.php) | `handle` |
1212
| `/api/checkpoint` | [`RequestHandlers\Api\Checkpoint`](../../src/RequestHandlers/Api/Checkpoint.php) | `handle` |
1313
| `/api/extensions` | [`RequestHandlers\Api\Extensions`](../../src/RequestHandlers/Api/Extensions.php) | `handle` |
1414
| `/api/history` | [`RequestHandlers\Api\History`](../../src/RequestHandlers/Api/History.php) | `handle` |
@@ -24,7 +24,7 @@ This document lists all API routes defined via `#[Route]` attributes.
2424
| `/api/replicas/{replica_id}/actor/{actor_id}/keys/key/{key_id}` | [`RequestHandlers\Api\ReplicaInfo`](../../src/RequestHandlers/Api/ReplicaInfo.php) | `actorKey` |
2525
| `/api/replicas/{replica_id}/history` | [`RequestHandlers\Api\ReplicaInfo`](../../src/RequestHandlers/Api/ReplicaInfo.php) | `history` |
2626
| `/api/replicas/{replica_id}/history/since/{hash}` | [`RequestHandlers\Api\ReplicaInfo`](../../src/RequestHandlers/Api/ReplicaInfo.php) | `historySince` |
27-
| `/api/revoke` | [`RequestHandlers\Api\BurnDown`](../../src/RequestHandlers/Api/BurnDown.php) | `handle` |
27+
| `/api/revoke` | [`RequestHandlers\Api\Revoke`](../../src/RequestHandlers/Api/Revoke.php) | `handle` |
2828
| `/api/server-public-key` | [`RequestHandlers\Api\ServerPublicKey`](../../src/RequestHandlers/Api/ServerPublicKey.php) | `handle` |
2929
| `/api/totp/disenroll` | [`RequestHandlers\Api\TotpDisenroll`](../../src/RequestHandlers/Api/TotpDisenroll.php) | `handle` |
3030
| `/api/totp/enroll` | [`RequestHandlers\Api\TotpEnroll`](../../src/RequestHandlers/Api/TotpEnroll.php) | `handle` |

public/index.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
if ($ex instanceof RateLimitException) {
3030
// Rate-limited by the Middleware
3131
http_response_code(420);
32+
if (!is_null($ex->rateLimitedUntil)) {
33+
header('Retry-After: ' . $ex->rateLimitedUntil->format(DateTimeInterface::ATOM));
34+
}
3235
echo $ex->getMessage(), PHP_EOL;
3336
if (!is_null($ex->rateLimitedUntil)) {
3437
echo 'Try again after: ',

src/Meta/Params.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function __construct(
2323
public string $hostname = 'localhost',
2424
public string $cacheKey = '',
2525
public int $httpCacheTtl = 60,
26+
public bool $serverAllowsBurnDown = true,
2627
) {
2728
if (!Tree::isHashFunctionAllowed($this->hashAlgo)) {
2829
throw new DependencyException('Disallowed hash algorithm');
@@ -49,6 +50,11 @@ public function getActorUsername(): string
4950
return $this->actorUsername;
5051
}
5152

53+
public function getBurnDownEnabled(): bool
54+
{
55+
return $this->serverAllowsBurnDown;
56+
}
57+
5258
public function getCacheKey(): string
5359
{
5460
return $this->cacheKey;

0 commit comments

Comments
 (0)