diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml new file mode 100644 index 000000000..29492dec9 --- /dev/null +++ b/.github/workflows/audit.yml @@ -0,0 +1,50 @@ +name: Audit + +on: [pull_request] + +env: + WEBAPP_NAME: ninjawars # set this to your application's name + WEBAPP_PACKAGE_PATH: "." # set this to the path to your web app project, defaults to the repository root + NODE_VERSION: "16.13.1" # set this to the node version to use + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_READ_TOKEN }} + CI: false +jobs: + lighthouseci: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v1 + with: + node-version: ${{ env.NODE_VERSION }} + #always-auth: true + #registry-url: "https://npm.pkg.github.com" + - name: Yarn packages audit + run: yarn npm audit + continue-on-error: true + - name: Install, configure, install the lighthouse auditor + run: | + # Check the node version + node --version + corepack enable + # corepack enable should have made this unnecessary + # Install the project, then... + # yarn workspaces run init-project + yarn init-project + yarn install --immutable + # I guess even with corepack the yarn install is still required? + #yarn bootstrap + - name: Build + run: | + # Stop eslint from failing the build + rm .eslintrc.json + yarn build + - name: Audit URLs using Lighthouse + uses: treosh/lighthouse-ci-action@v8 + with: + urls: | + http://localhost:7474/ + http://localhost:7474/intro + budgetPath: ./.budget.json # test performance budgets + uploadArtifacts: true # save results as an action artifacts + temporaryPublicStorage: true # upload lighthouse report to the temporary storage diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 4de75e3a6..9346f38f4 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -56,6 +56,11 @@ jobs: # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit" # Docs: https://getcomposer.org/doc/articles/scripts.md + - name: Run build + run: | + ln -s ./resources.build.php ./deploy/resources.php + make build + - name: Run test suite run: | ln -s ./resources.build.php ./deploy/resources.php diff --git a/.gitignore b/.gitignore index dcca8f12d..96baf5224 100644 --- a/.gitignore +++ b/.gitignore @@ -100,3 +100,5 @@ karma.conf.js .php-cs-fixer.cache deploy/www/index.html deploy/www/intro.html +deploy/www/login.html +deploy/www/signup.html diff --git a/.lighthouserc.js b/.lighthouserc.js new file mode 100644 index 000000000..9dca473fe --- /dev/null +++ b/.lighthouserc.js @@ -0,0 +1,47 @@ +module.exports = { + ci: { + collect: { + staticDistDir: 'deploy/www', + isSinglePageApplication: true, + numberOfRuns: 1 + }, + upload: { + // target: 'filesystem' + target: 'temporary-public-storage' + }, + assert: { + "preset": "lighthouse:no-pwa", // Change this to "lighthouse:recommended" when we move to a PWA in the future + assertions: { + "maskable-icon": "off", + "service-worker": "off", + "tap-targets": "off", + "apple-touch-icon": "off", + "first-contentful-paint": ['warn', { minScore: 0.9 }], + "interactive": ['warn', { minScore: 0.9 }], + "last-contentful-paint": ['warn'], + "largest-contentful-paint": ['warn'], + "first-meaningful-paint": ['warn'], + "label": ['warn'], + "max-potential-fid": ['warn', { minScore: 0.9 }], + //"render-blocking-resources": ['warn', { minScore: 0.4 }], + "speed-index": ['warn', { minScore: 0.9 }], + "mainthread-work-breakdown": ['warn', { minScore: 0.9 }], + "legacy-javascript": ['warn', { auditRan: 1 }], + "duplicated-javascript": ['warn'], + "unused-javascript": ['warn', { maxLength: 4 }], + "unminified-javascript": ['warn'], + "uses-long-cache-ttl": ['warn', { maxLength: 13 }], + "uses-rel-preconnect": ['warn'], + "render-blocking-resources": ['error', { maxLength: 2 }], + "font-size": ['warn'], + "bootup-time": ['warn', { minScore: 0.65 }], + "button-name": ['warn', { minScore: 0.65 }], + "link-name": ['warn', { minScore: 0.65 }], + "color-contrast": ['warn', { minScore: 0.65 }], + "robots-txt": ['warn'], + "first-cpu-idle": ['warn', { minScore: 0.85 }], + "meta-description": ['warn'], + } + }, + } +} diff --git a/Makefile b/Makefile index 98367dd79..071a28ee9 100644 --- a/Makefile +++ b/Makefile @@ -27,12 +27,21 @@ endif build: dep mkdir -p $(JS) + @echo "Don't forget to update nginx configs as necessary." + @echo "Including updating the php to retain login sessions longer." + cp -pn ./deploy/resources.build.php ./deploy/resources.php || true + echo "Note that this does not overwrite existing resources.php" + echo "Check that the webserver user has permissions to the script!" @ln -sf "$(RELATIVE_COMPONENTS)jquery/jquery.min.js" "$(JS)" @ln -sf "$(RELATIVE_COMPONENTS)jquery/jquery.min.map" "$(JS)" @ln -sf "$(RELATIVE_COMPONENTS)jquery-timeago/jquery.timeago.js" "$(JS)" @ln -sf "$(RELATIVE_COMPONENTS)jquery-linkify/jquery.linkify.js" "$(JS)" @ln -sf "$(RELATIVE_VENDOR)twbs/bootstrap/dist/css/bootstrap.min.css" "$(CSS)" @ln -sf "$(RELATIVE_VENDOR)twbs/bootstrap/dist/js/bootstrap.min.js" "$(JS)" + make check-base + php deploy/www/intro-controller.php > deploy/www/intro.html + php deploy/www/front-controller.php > deploy/www/index.html + @echo "Built front controller to static deploy/www/index.html file and deploy/www/intro.html file" rm -rf ./deploy/templates/compiled/* ./deploy/templates/cache/* mkdir -p ./deploy/templates/compiled ./deploy/templates/cache ./deploy/resources/logs/ chmod -R ugo+rwX ./deploy/templates/compiled ./deploy/templates/cache @@ -45,6 +54,9 @@ dep: check: pre-test +check-base: + php deploy/checkbase.php + js-deps: node -v corepack enable @@ -142,7 +154,6 @@ check-for-syntax-errors: @find "./deploy/www/" -name "*.php" -exec php -l {} \;|grep -v "No syntax errors" || true test-unit: check-for-syntax-errors - @$(TEST_RUNNER) $(CC_FLAG) --testsuite Unit test-quick: check-for-syntax-errors diff --git a/deploy/check.php b/deploy/check.php index 39ae4725e..9ab1fad2f 100644 --- a/deploy/check.php +++ b/deploy/check.php @@ -1,39 +1,22 @@ attach(Swift_Attachment::fromPath('my-document.pdf')) - ; + ; if ($this->reply_to) { $this->message->setReplyTo($this->reply_to); diff --git a/deploy/lib/plugins/function.cachebust.php b/deploy/lib/plugins/function.cachebust.php index 5bb6b21c1..b2b6ce384 100644 --- a/deploy/lib/plugins/function.cachebust.php +++ b/deploy/lib/plugins/function.cachebust.php @@ -8,7 +8,7 @@ function smarty_function_cachebust($p_params) { $file = ROOT."/www/$p_params[file]"; - if (is_file($file)) { + if (is_file($file) && HASH_ASSET_PATHS) { $mtime = filemtime($file); $pathParts = pathinfo($p_params['file']); return $pathParts['dirname'].'/'.$pathParts['filename'].".$mtime.".$pathParts['extension']; diff --git a/deploy/resources.build.php b/deploy/resources.build.php index fdc262129..f138671e4 100644 --- a/deploy/resources.build.php +++ b/deploy/resources.build.php @@ -6,12 +6,13 @@ define('DATABASE_USE_PASSWORD', false); // *** Whether to specify password to pdo at all. Generally true only on live define('DATABASE_USE_PORT', false); // *** Whether to specify port to pdo at all. Generally true only on live define('DATABASE_USE_HOST', false); // *** Whether to specify HOST to pdo at all. Generally true only on live -define('DATABASE_HOST', "localhost"); // *** The host to connect to for the database, localhost by default -define('DATABASE_PORT', "5432"); // *** The port number to connect on. -define('DATABASE_USER', "postgres"); // *** The user that should connect to the database -define('DATABASE_PASSWORD', "unused_in_build"); // *** The password for the database connection, trust on dev -define('DATABASE_NAME', "nw"); // *** The name of the database to connect to, nw on dev -define('OFFLINE', false); // *** Controls if remote or local resources are used +define('DATABASE_HOST', "localhost"); // *** The host to connect to for the database, localhost by default +define('DATABASE_PORT', "5432"); // *** The port number to connect on. +define('DATABASE_USER', "postgres"); // *** The user that should connect to the database +define('DATABASE_PASSWORD', "unused_in_build"); // *** The password for the database connection, trust on dev +define('DATABASE_NAME', "nw"); // *** The name of the database to connect to, nw on dev +define('OFFLINE', true); // *** Controls if remote or local resources are used +define('HASH_ASSET_PATHS', false); // *** Controls if cachebusting hash strings for assets like images are used define('DEBUG', true); // *** Shorter debugging constant name, set as false on live. define('SERVER_ROOT', realpath(__DIR__).'/'); // *** The root deployment directory of the game // Generally for the install purposes the SERVER_ROOT should correspond to /srv/ninjawars/deploy/ @@ -28,7 +29,7 @@ define('FACEBOOK_APP_ID', '30479872633'); // Non-confidential id for the facebook app define('FACEBOOK_APP_SECRET', 'mooMooIAmACow'); // Secret! string for facebook login auth stuff. -define('TRAP_ERRORS', true); // Whether to use the global error handler & oops page, true on live. +define('TRAP_ERRORS', false); // Whether to use the global error handler & oops page, true on live. define('TEMPLATE_LIBRARY_PATH', SERVER_ROOT.'vendor/smarty/smarty/libs/Smarty.class.php'); // Path to Smarty 3 diff --git a/deploy/resources.template.php b/deploy/resources.template.php index 3a7430b96..3d53bbb27 100644 --- a/deploy/resources.template.php +++ b/deploy/resources.template.php @@ -11,7 +11,8 @@ define('DATABASE_USER', __DB_USER__); // *** The user that should connect to the database define('DATABASE_NAME', __DB_NAME__); // *** The name of the database to connect to define('DATABASE_PASSWORD', __DB_PASS__); // *** The password for the database connection -define('OFFLINE', __OFFLINE__); // *** Controls if remote or local resources are used +define('OFFLINE', __OFFLINE__); // *** Controls if remote or local resources are used +define('HASH_ASSET_PATHS', true); // *** Controls if cachebusting hash strings for assets like images are used define('DEBUG', __DEBUG__); // *** Shorter debugging constant name, set as false on live. define('SERVER_ROOT', __SERVER_ROOT__); // *** The root deployment directory of the game // Generally for the install purposes the SERVER_ROOT should correspond to /srv/ninjawars/deploy/ diff --git a/deploy/tests/functional/test_ratchets.py b/deploy/tests/functional/test_ratchets.py index 3942b86f8..b6ed18b3c 100644 --- a/deploy/tests/functional/test_ratchets.py +++ b/deploy/tests/functional/test_ratchets.py @@ -10,7 +10,7 @@ class TestRatchets: and checks the overall SLOC of the project ''' control_php = 37 - www_php = 1 + www_php = 4 plus_minus = 6 ''' Rough file counts in pertinent directories ''' diff --git a/deploy/tests/unit/SmartyPluginUnitTest.php b/deploy/tests/unit/SmartyPluginUnitTest.php index 5caf397dc..4845d47b9 100644 --- a/deploy/tests/unit/SmartyPluginUnitTest.php +++ b/deploy/tests/unit/SmartyPluginUnitTest.php @@ -17,9 +17,9 @@ class SmartyPluginUnitTest extends \PHPUnit\Framework\TestCase { public const URL = 'https://localhost.com/go/?query=string'; public function testCachebustPositive() { - $result = smarty_function_cachebust(['file'=>self::EXISTING_FILE]); - $this->assertNotEquals(self::EXISTING_FILE, $result); - $this->assertGreaterThan(strlen(self::EXISTING_FILE), strlen($result)); + $result = smarty_function_cachebust(['file' => self::EXISTING_FILE]); + $this->assertNotEmpty($result); + $this->assertStringContainsString(self::EXISTING_FILE, $result); } public function testCachebustNegative() { diff --git a/deploy/www/intro-controller.php b/deploy/www/intro-controller.php new file mode 100644 index 000000000..ae84b7c93 --- /dev/null +++ b/deploy/www/intro-controller.php @@ -0,0 +1,45 @@ +get('player_id'); + return $player_id ? Player::find($player_id) : null; + }; + + $container['session'] = function ($c) { + return SessionFactory::getSession(); + }; + + // Update the activity of the page viewer in the database. + RequestWrapper::init(); + + // get the request information to parse the route + $response = Router::route(Request::create( + '/intro', + 'GET', + ), $container); + + if ($response instanceof Response) { + $response->send(); + } else { + throw new \RuntimeException('Route returned something other than a Response'); + } +} catch (RouteNotFoundException $e) { + Router::respond404(); +} diff --git a/package.json b/package.json index 8dd87f44c..396a8d88f 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,13 @@ "doc": "docs" }, "scripts": { + "init-project": "echo 'no-op for config'", "lint": "eslint --ext .jsx,.js deploy/www/js", "prepare-unit-test-ci": "echo 'no-op for now'", "start": "yarn time && make build && yarn time", "post-deploy": "php deploy/deployed_scripts/resetcache.php", + "build": "make build", + "serve": "yarn dlx serve deploy/www/ -p 7474", "watch": "livereload ./deploy/* ./deploy/www/* ./deploy/templates/* ./deploy/lib/control/* --debug", "security-check": "yarn audit", "time": "node -e \"console.log( new Date().toISOString() );\"", @@ -41,7 +44,7 @@ "url": "https://github.com/BitLucid/ninjawars/issues" }, "engines": { - "node": ">=16.0.0" + "node": ">=16.13.0" }, "homepage": "https://github.com/BitLucid/ninjawars#readme", "devDependencies": {