aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAge
...
* Remember to free the numcolours array from Pattern's drawstateBen Harris2023-02-13
|
* Don't leak duplicate edges in UntangleBen Harris2023-02-13
| | | | | | | Untangle game descriptions are allowed to contain duplicate edges, and add234() can handle deduping them. However, when add234() reports that your newly-allocated edge is a duplicate, it's important to free it again.
* Undead: check the return value of sscanf() in execute_move()Ben Harris2023-02-13
| | | | | | | | | | sscanf() assigns its output in order, so if a conversion specifier fails to match, a later "%n" specifier will also not get its result assigned. In Undead's execute_move(), this led to the result of "%n" being used without being initialised. That could cause it to try to parse arbitrary memory as part of the move string, which shouldn't be a security problem (since execute_move() handles untrusted input anyway), but could lead to a crash and certainly wasn't helpful.
* Remember to free the to_draw member from Net's drawstateBen Harris2023-02-13
|
* Don't leak grids in Loopy's validate_desc()Ben Harris2023-02-13
|
* Remember to free the actual_board array in MosaicBen Harris2023-02-13
|
* Fix memory leaks in Keen's validate_desc()Ben Harris2023-02-13
| | | | | Keen uses a DSF to validate its game descriptions and almost always failed to free it, even when the validation succeeded.
* Allow more general cross-shaped boards in PegsBen Harris2023-02-12
| | | | | | | I found a plausible looking Web page claiming that various different sizes of cross are soluble, and some of them are quite widespread. I've enabled the ones that are symmetric enough that the existing game generator can lay them out.
* Don't allow moves that change the constraints in UnequalBen Harris2023-02-11
| | | | | | | | | | | | | | | | | | | | | | | Unequal has a flags word per cell. Some of those flags are fixed, like the locations of the ">" signs, but others indicate errors and are used to allow the player to mark clues as "spent". Move strings beginning with "F" allow the user to change the "spent" flags, but they shouldn't allow the user to change any other flags, especially those marking the constraints. Without this fix, the following save file gives a "solver_nminmax: Assertion `x >= 0 && y >= 0 && x < o && y < o' failed" after it adds a clue that points off the board: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :7:Unequal PARAMS :3:3e0 CPARAMS :3:3e0 DESC :17:0,0,0,0,0,0,0,0,0 NSTATES :2:3 STATEPOS:1:3 MOVE :6:F2,0,4 MOVE :1:H
* Cleanly reject more ill-formed solve moves in FloodBen Harris2023-02-11
| | | | | | | | | | | | | The fix in e4112b3 was incomplete: there was another assertion that could be failed by a save file with an ill-formed solve move. That now gets rejected properly. Here's an example save file to demonstrate the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :5:Flood PARAMS :7:6x6c6m0 CPARAMS :7:6x6c6m0 DESC :39:000000000000000000000000000000000000,00 NSTATES :1:2 STATEPOS:1:2 MOVE :1:S
* Check state is valid at the end of a move in PearlBen Harris2023-02-11
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | A Pearl move string contains a sequence of sub-moves, each of which can affect the state of the connection between the centre of a square and one of its edges. interpret_move() generates these in pairs so that the two halves of a connection between the centres of adjacent squares stay in the same state. If, however, a save file contains mismatched half-moves, execute_move() should ideally return NULL rather than causing an assertion failure. This has to be checked at the end of the whole move string, so I've arranged for check_completion() to return a boolean indicating whether the current state (and hence the move preceding it) is valid. It now returns 'false' when a connection stops at a square boundary or when it goes off the board. These conditions used to be assertion failures, and now they just cause the move to be rejected. This supersedes the check for off-board connections added in 15f4fa8, since now check_completion() can check for off-board links for the whole board at once. This save file trivially demonstrates the problem, causing "dsf_update_completion: Assertion `state->lines[bc] & F(dir)' failed" without this fix: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :5:Pearl PARAMS :5:6x6t0 CPARAMS :5:6x6t0 DESC :17:BbBfWceBbWaBWWgWB NSTATES :1:2 STATEPOS:1:2 MOVE :6:R1,0,0
* Mention how old the 15-puzzle isBen Harris2023-02-11
| | | | | | | For most puzzles, the manual tries to at least mention its origin. Wikipedia suggests that the precise inventor of the 15-puzzle is a bit uncertain, but US patent number 207124 definitely describes it in 1878, so "dates from the 1870s" seems pretty solid.
* Forbid game descriptions with joined islands in BridgesBen Harris2023-02-10
| | | | | | | | | | A game description with islands in adjacent grid squares, like "3x3:11g", shouldn't be allowed. If it is, then bridges between the islands are invisible and clicking one of them causes an assertion failure: "Assertion `is_loop->adj.points[j].off > 1' failed." The code to check this is really rather complex, but I think the complexity is mostly necessary.
* Forbid impossible moves in BridgesBen Harris2023-02-10
| | | | | | | | | | | | | | | | | | | | Specifically, a bridge or a non-bridge must connect two islands that differ in precisely one co-ordinate. Without this, a save file that tries to connect or disconnect two non-orthogonal islands will cause "island_join: Assertion `!"island_join: islands not orthogonal."' failed." Here's a save file demonstrating the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Bridges PARAMS :13:3x3i30e10m2d0 CPARAMS :13:3x3i30e10m2d0 DESC :6:b1c1a2 NSTATES :1:2 STATEPOS:1:2 MOVE :10:L0,2,2,0,1
* Unequal: fix sense error in latin_solver_alloc fix.Simon Tatham2023-02-08
| | | | | | | | | | In commit 5030d87903191d5 I gave latin_solver_alloc a return value, and introduced a check of that value at every call site. One of the checks was backwards, with the effect that Unequal game generation now more or less always fails an assertion. For example: $ unequal --generate 1 4#12345 unequal: unequal.c:1072: gg_best_clue: Assertion `best != -1' failed.
* Mines: Add assertions to range-check conversions to shortBen Harris2023-02-05
| | | | | I think these should be adequately guarded by the new restrictions on grid size, but I'd prefer to be sure.
* Limit width and height to SHRT_MAX in MinesBen Harris2023-02-05
| | | | | | | | | | | | | | | | | | | | | Mines' "struct set" stores co-ordinates within the grid in a pair of shorts, which leads to very bad behaviour (including heap-based buffer overruns) if the grid is bigger than SHRT_MAX in either dimension. So now we don't allow that. The overrun can be demonstrated by loading this save file, though the precise crash is quite variable. In particular, you seem to get better crashes if the file doesn't have a trailing newline. SAVEFILE:41:Simon Tatham's Portable Puzzle Collection PARAMS :5:06000 CPARAMS :7:6x60000 NSTATES :1:3 STATEPOS:1:2 MOVE :5:C0,00 GAME :5:Mines DESC :22:r8,u,00000000000000000 MOVE ::
* Range: Don't fail an assertion on an all-black boardBen Harris2023-02-05
| | | | | | | | If there are no white squares, then Range's check that all the white squares form a connected component goes wrong. Skip the check in that case to avoid an assretion violation ("edsf_canonify: Assertion `index >= 0' failed."). This can be demonstrated by starting a game with no clues (e.g. "range 3:i") and then filling in every square.
* Unequal: Don't insist that solve moves must actually solveBen Harris2023-02-05
| | | | | | | | | | | | | | | | | | | A corrupt save file can include an "S" move that doesn't give a valid solution. An assertion failure ("execute_move: Assertion `rc > 0' failed.") at that point is rude, so now we just don't set the "completed" flag in that case. We still set the "cheated" flag, to reward (lack of) effort. Here's a trivial test case: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :7:Unequal CPARAMS :1:3 PARAMS :1:3 DESC :17:0,0,0,0,0,0,0,0,0 NSTATES :1:2 STATEPOS:1:2 MOVE :10:S222222222
* Pearl: fix bounds check in previous commit.Simon Tatham2023-02-05
| | | | Ahem. That's what I get for testing the fix on a square puzzle.
* Pearl: fix assertion failure on bad puzzle.Simon Tatham2023-02-05
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Similarly to the previous commit, if you started Pearl with at least some kinds of invalid puzzle (e.g. "6x6:abBfWcWWrBa") and then pressed 'h' to get hints, you could provoke an assertion failure. But this time the assertion wasn't in the solver itself; the solver gave up gracefully and didn't crash, but it _did_ leave the links between squares in the game_state in an inconsistent state, in that one square was marked as linking to its neighbour without the neighbour also linking back to it. This caused the /* should have reciprocal link */ assertion in dsf_update_completion to fail, when that was called from check_completion after the solver had finished, to decide whether the puzzle was now solved. In this commit, I arrange that whether or not pearl_solve returns a grid layout that's legal by the rules of the _puzzle_, it at least returns one that's legal by the rules of the _data representation_, in that every link between squares is either bidirectional or absent. This is a better solution than just removing the assertion, because if the inconsistent data were allowed to persist, it would lead to further problems in gameplay. For example, if you just remove that assertion instead of this fix and press 'h' on the example puzzle id above, you'll find that the non-reciprocal links are actually visible, in the form of several thick lines that stop at a grid square boundary instead of connecting two square-centres. (It looks even sillier if you set PEARL_GUI_LOOPY=y.) That's a situation that can't be created by a normal move, and if you try to make normal moves after it (e.g. click one of the weird edges), you'll find that both sides of the half-link get toggled, so now it's a half-link the other way round. So not only can't you _create_ this situation in normal play, you can't get rid of it either! That assertion in dsf_update_completion was commented out at one point, and I put it back in commit c5500926bf7458a saying that if it failed I'd like to know about it. And indeed, I'm glad I did, because this kind of unfixable wrongness in the resulting game_state was worth noticing and getting rid of!
* latin_solver_alloc: handle clashing numbers in input grid.Simon Tatham2023-02-05
| | | | | | | | | | | | | | | | | | | | | In the setup phase of the centralised latin.c solver, we start by going over the input grid containing already-placed clue numbers, and calling latin_solver_place to enter each on into the solver's data structure. This has the side effect of ruling out each number from the rest of the row and column, and _also_ checking by assertion that the number being placed is not ruled out. Those are a bad combination, because it means that if you give an obviously inconsistent input grid to latin_solver_alloc (e.g. with two identical numbers in a row already), it will fail an assertion. In that situation, you want the solver run as a whole to return diff_impossible so that the error is reported cleanly. This assertion failure could be provoked by giving either Towers or Group a manually-constructed game description inconsistent in that way, and hitting Solve. Worse, it could be provoked during live play in Unequal, by filling in a number clashing with a clue and then pressing 'h' to get hints.
* Palisade: replace dfs_dsf() with a simple iteration.Simon Tatham2023-02-03
| | | | | | | | | | | | | | | | | | | | | | | | | | | The whole purpose of a dsf is that you can traverse the edges of your graph in any order you feel like. So if you want to build the connected components of a graph you can just loop over all the edges once. There's no need to run a depth-first search. In fact there were an amazing number of things wrong with this 10-line function: - As Ben points out in commit 21193eaf9308ace, it didn't bother with bounds checking when searching the grid, instead relying on the never-removed grid boundary to stop the search - which was fragile in the face of other bugs. - The recursion uses linear stack, which is much worse than linear heap, since stacks are often much more limited. (And the dsf _also_ used linear heap.) - The recursion was completely unnecessary. - The function used internal knowledge about dsf.c in order to define the value UNVISITED to match what would happen to work. - The name 'dfs_dsf' is totally confusing and almost impossible to type!
* Tolerate incorrect solutions in InertiaBen Harris2023-02-03
| | | | | | | | | | | | | | | | | | | | | | | | | | The "solve" operation in Inertia generates a proposed solution as a move string. But if such a move string is loaded from a save file it might not actually describe a solution. If that happens then it's possible to reach the end of the "solution" without winning, and doing so should probably cause a recalculation of the solution rather than an assertion failure ("execute_move: Assertion `ret->solnpos < ret->soln->len' failed."). I am a little concerned by the way that normal solve operations end up encoded in the save file, but the re-solvings caused by going off course don't, but I haven't got a good answer to that. Here's a save file that demonstrates the assertion failure: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :7:Inertia PARAMS :3:8x8 CPARAMS :3:8x8 DESC :64:sbgwsmswwgggwggmmbwgwbssbwbsbwbbwsSmwbbsbbmggbmssgmgwbmmwmbmmwsw NSTATES :2:3 STATEPOS:1:1 MOVE 000:2:S0 MOVE 000:2:00
* Forbid lines off the grid in PearlBen Harris2023-02-02
| | | | | | | | | | | | | | | | | | | | | | While they couldn't be generated in normal play, execute_move() would permit lines and marks across the edge of the grid that would then generate assertion failures ("dsf_update_completion: Assertion `INGRID(state, bx, by)' failed."). I've added a check to execute_move() that after updating a square, the square doesn't have any lines or marks that leave the grid. This save file demonstrated the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSZON :1:1 GAME :5:Pearl PARAMS :5:5x6dt CPARAMS :5:5x6dt DESC :6:eeeeee NSTATES :1:2 STATEPOS:1:1 MOVE :6:F1,4,2
* Dominosa: require the two halves of a domino to be adjacentBen Harris2023-02-02
| | | | | | | | | | | | | | | | | | | Also that a line indicating no domino be between adjacent squares. Without this, execute_move would allow you to place dominos and edges between any pair ot squares, and then generate assertion failures ("execute_move: Assertion `d2 - w >= 0' failed." and "execute_move: Assertion `d1 - w >= 0' failed.") when a domino was placed over an invalid edge. This example save file demonstrates the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :8:Dominosa PARAMS :1:6 CPARAMS :1:6 DESC :56:55521461210004364611033535444421636022603153156422620503 NSTATES :1:3 STATEPOS:1:3 MOVE :4:E0,2 MOVE :4:D0,2
* Tighten validation of Tents game descriptionsBen Harris2023-02-02
| | | | | | | | | | Specifically, TENT and NONTENT markers ('!' and '-') cannot appear as the first or last character of a description, because that would attempt to place them on squares outside the grid. This was caught by assertions in new_game(), as can be demonstrated by feeding these descriptions to older versions of Tents: "4:-p,0,0,0,0,0,0,0,0" ("new_game: Assertion `i >= 0 && i <= w*h' failed.") and 4:p-,0,0,0,0,0,0,0,0 ("new_game: Assertion `*desc == ','' failed.").
* Fix move validation in NetslideBen Harris2023-02-01
| | | | | | | | | | | | | | | | | | | | The maximum length of a column move in Netslide is the height of the puzzle, and the maximum length of a row move is the width, not the other way around. Moves of absolute length more than 1 can't be generated by interpret_move(), but they can come from save files. On non-square grids, the incorrect check led to assertion failures: "0 <= tx && tx < w" and "0 <= ty && ty < h". This save file demonstrates the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :8:Netslide PARAMS :3:4x9 CPARAMS :3:4x9 DESC :39:0000000000000h0h0000000000000000000000v NSTATES :1:2 STATEPOS:1:2 MOVE :4:R0,5
* Avoid invalid moves when solving TracksBen Harris2023-02-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The solver, when it decided that an edge or square should be both TRACK and NOTRACK, would correctly decide that the puzzle was insoluble, but would also mark the edge with both flags in its working copy. This could then lead to assertion violations if that working copy of the board was used for something else, for instance if it was fed back into the solver. This couldn't happen in normal play, since failed solutions just cause the solve command to fail, but the diagnostic "H" command could trigger it from a save file, causing an assertion failure: "state->sflags[y*state->p.w + x] & S_CLUE". Now when the solver runs into this situation, it marks the puzzle as insoluble but doesn't set the invalid flag, so the board remains valid and future solve operations are safe. This save file is the one that demonstrated the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :12:Train Tracks PARAMS :5:6x6t0 CPARAMS :5:6x6t0 DESC :31:b0t9l,,S0,00,0,0,4,0,0,S0,0,0,0 NSTATES :1:8 STATEPOS:1:2 MOVE :1:H MOVE :1:H MOVE :1:H MOVE :1:H MOVE :1:H MOVE :1:H MOVE :1:H
* Mines: Don't check if the player has won if they've already lostBen Harris2023-02-01
| | | | | | | | | | | | | | | | | | | | | | | It can't happen in normal play, but if a save file had a "C" (clear around) move that set off a mine, Mines could end up hitting an assertion failure, "ncovered >= nmines". This was because it would check if the player had won by counting covered squares and mines, and of course an uncovered mine is no longer a covered square but is still a mine. Since winning after you're dead isn't possible (at least in Mines), we now skip the check entirely if the player has already died. This save file demonstrates the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection GAME :5:Mines PARAMS :1:7 CPARAMS :1:7 DESC :22:r31,u,0000C000d0000020 NSTATES :1:2 STATEPOS:1:1 MOVE :4:C6,2
* Mines: forbid moves that flag or unflag an exposed squareBen Harris2023-02-01
| | | | | | | interpret_move() couldn't generate them, but execute_move() also needs to forbid them to defend against corrupt save files. I don't think this actually caused any crashes, but it did cause unexpected "1" squares not adjacent to mines.
* Document numeric input in UndeadBen Harris2023-02-01
| | | | | I was able to guess what the keys were, but I think it's polite to write it down for people with numeric-only keyboards.
* Remove an odd mention of NO_PRINTING from MosaicBen Harris2023-01-31
|
* Explicitly document that various function pointers can be NULLBen Harris2023-01-31
| | | | | | | | There are various functions pointed to by the game structure that are only called if certain flags are set. Some of them were documented as not being called when the flags were clear, but there was no explicit statement that the pointers could simply be NULL in that case. Now there is.
* Remove various unused game functionsBen Harris2023-01-31
| | | | | | | | | | | | | | | | | | | | If can_configure is false, then the game's configure() and custom_params() functions will never be called. If can_solve is false, solve() will never be called. If can_format_as_text_ever is false, can_format_as_text_now() and text_format() will never be called. If can_print is false, print_size() and print() will never be called. If is_timed is false, timing_state() will never be called. In each case, almost all puzzles provided a function nonetheless. I think this is because in Puzzles' early history there was no "game" structure, so the functions had to be present for linking to work. But now that everything indirects through the "game" structure, unused functions can be left unimplemented and the corresponding pointers set to NULL. So now where the flags mentioned above are false, the corresponding functions are omitted and the function pointers in the "game" structures are NULL.
* Loopy: Specify can_solve as true, rather than 1Ben Harris2023-01-31
|
* Validate the number of pegs and holes in a Pegs game IDBen Harris2023-01-28
| | | | | | | Without this, "1:O" causes an assertion violation, '!"new_ui found nowhere for cursor"'. We may as well require two pegs and one hole, since that's the minimum for a game in which there are any moves to make.
* Limit number of mines in Mines game descriptionBen Harris2023-01-28
| | | | | | | | Without this, it's possible to specify a description that has more mines than there are places on the board to place them, which eventually leads to a division by zero. This can be demonstrated by entering a game description of "3:r8,u," and then clicking anywhere on the board.
* Don't segfault on premature solve moves in MinesBen Harris2023-01-28
| | | | | | | | | | | | | | | | | | | | | If a save file contained a solve move as the first move, Mines would dereference a null pointer trying to look up the (at that point undetermined) mine locations. Now execute_move() politely returns NULL instead. This save file demonstrates the problem: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Mines PARAMS :5:3x3n0 CPARAMS :5:3x3n0 DESC :127:r0,u,7a142789cabddc3fc4dcb7d2baa4a4937b33c9613ea870ac098e217981ad339930af585557d62048ea745d05b01475d9699596b394cc0adeebf0440a02 UI :2:D0 TIME :1:0 NSTATES :1:2 STATEPOS:1:2 SOLVE :1:S
* Cleanly reject ill-formed solve moves in FloodBen Harris2023-01-28
| | | | | | | | | | | | | | | | | | | A solve move containing characters other than digits and commas would cause an assertion failure, "*p == ','", in execute_move(). Such a move can't as far as I know be generated in play, but can be read from a corrupt save file. Here's a sample of such a save file: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Flood PARAMS :7:3x3c6m5 CPARAMS :7:3x3c6m5 DESC :12:403011503,10 NSTATES :1:2 STATEPOS:1:2 SOLVE :2:SA
* Forbid moves that fill with the current colour in FloodBen Harris2023-01-28
| | | | | | | | | | | | | | | | | | This avoids an assertion failure, "oldcolour != newcolour" in fill(), by catching it it execute_move(). As far as I know this couldn't be triggered from the UI, but it could be demonstrated with this save file: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Flood PARAMS :1:3 CPARAMS :1:3 DESC :12:231353400,11 NSTATES :1:3 STATEPOS:1:3 MOVE :2:M3 MOVE :2:M3
* Don't allow Bridges games with < 2 islandsBen Harris2023-01-28
| | | | | | | | | | | | | | | | | | | Technically, a game with no islands is always solved, but it causes a null-pointer dereference at startup because there's nowhere to put the cursor. Games with one island are always insoluble because the island must have at least one bridge and there's nowhere for it to go. So the minimum playable game has two islands. To demonstrate the segfault, try loading this save file: SAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Bridges PARAMS :1:3 CPARAMS :1:3 DESC :1:i NSTATES :1:1 STATEPOS:1:1
* Move KaiAds menu optionBen Harris2023-01-23
| | | | | | | | It's a bit of a nuisance at the moment if you're trying to get to the documentation by pressing the up arrow, so I've moved it above the documentation links, which is where I keep expecting to find it. I probably want to do some larger-scale menu re-organisation on KaiOS, though.
* KaiOS: explicitly set the font family to Open SansBen Harris2023-01-23
| | | | | | | This means that you'll get the right font if you one the app page on a desktop browser (assuming you have Open Sans installed). Also my Nokia 800 Tough seems to default to a different font (maybe Noto Sans?) and I'd prefer to have the same font everywhere.
* Increase KaiAds timeout to 10 secondsBen Harris2023-01-22
| | | | | | Kai recommend five to ten seconds, and five seconds is short enough that I get timeouts when testing that are hard to distinguish from having screwed up my content security policy.
* Add validate_params bounds checks in a few more games.Simon Tatham2023-01-22
| | | | | | | | | | | | | | | | | Ben tells me that his recent work in this area was entirely driven by fuzzing: he added bounds checks in validate_params when the fuzzer had managed to prove that the lack of them allowed something buggy to happen. It seemed worth doing an eyeball-review pass to complement that strategy, so in this commit I've gone through and added a few more checks that restrict the area of the grid to be less than INT_MAX. Notable in this commit: cube.c had to do something complicated because in the triangular-grid modes the area isn't calculated as easily as w*h, and Range's existing check that w+h-1 < SCHAR_MAX is sufficient to rule out w*h being overlarge _but_ should be done before w*h is ever computed.
* Black Box: reject negative ball counts in game_params.Simon Tatham2023-01-22
| | | | | | | | | | | | | | | You can inject one via a game desc string such as "10x10M5m-1", and it's clearly silly. _Zero_ balls, on the other hand, are a perfectly fine number: there's nothing incoherent about a BB puzzle in which the possible numbers of balls vary from (say) 0 to 5 inclusive, so that part of the challenge is to work out as efficiently as possible whether there are even any balls at all. (We only need to check minballs, because once we know minballs >= 0, the subsequent check ensures that maxballs >= minballs, and hence, by transitivity, maxballs >= 0 too.)
* Add myself to copyright holders and update copyright yearsBen Harris2023-01-21
| | | | | The KaiOS port is big enough that I think I'm worth mentioning, and it was released in 2023.
* Add a content security policy for the KaiOS appBen Harris2023-01-21
| | | | | | | This is for defence in depth against security holes either in Puzzles or in the KaiAds API. I haven't found any documentation of what KaiAds' CSP requirements are, but allowing scripts and frames from *.kaiads.com seems to be enough to let the test adverts work.
* Update comment in manifest.pl based on experienceBen Harris2023-01-21
| | | | | As far as I can tell, the KaiStore is quite happy with YY.MM.DD version numbers.