From 367ed82e562d0ef086fbf6390f3d0eabbbc61613 Mon Sep 17 00:00:00 2001
From: Annika <56906084+AnnikaCodes@users.noreply.github.com>
Date: Tue, 21 Jul 2020 15:27:21 -0700
Subject: [PATCH] Support configurable URLs (#1543)
---
.gitignore | 2 +
action.php | 10 +-
build-tools/build-indexes | 26 +++---
build-tools/build-learnsets | 2 +-
build-tools/build-minidex | 2 +-
build-tools/update | 91 ++++++++++++++-----
config/config-example.inc.php | 5 +
config/config-example.js | 11 +++
config/routes.json | 7 ++
crossdomain.php | 6 +-
...otocol.html => crossprotocol.template.html | 0
customcss.php | 9 +-
index.template.html | 3 +-
js/client-battle.js | 2 +-
js/client-chat.js | 2 +-
js/client-ladder.js | 2 +-
js/client-mainmenu.js | 4 +-
js/client-rooms.js | 3 +-
js/client-teambuilder.js | 4 +-
js/client-topbar.js | 2 +-
js/client.js | 16 ++--
...play-embed.js => replay-embed.template.js} | 2 +-
js/storage.js | 26 ++----
lib/dispatcher.lib.php | 6 +-
lib/ntbb-ladder.lib.php | 2 +-
lib/ntbb-session.lib.php | 24 ++---
preactalpha.template.html | 1 +
replays/battle.php | 13 +--
replays/build | 36 +++++---
replays/warstory.php | 22 ++---
src/battle-animations-moves.ts | 42 ++++-----
src/battle-animations.ts | 11 +++
src/battle-dex.ts | 17 +---
src/battle-log.ts | 12 +--
src/battle-searchresults.tsx | 2 +-
src/client-connection.ts | 2 +-
src/client-core.ts | 7 +-
src/client-main.ts | 16 ++--
src/panel-mainmenu.tsx | 22 ++---
src/panel-topbar.tsx | 6 +-
src/panels.tsx | 2 +-
testclient-beta.html | 1 +
testclient.html | 4 +-
43 files changed, 278 insertions(+), 207 deletions(-)
create mode 100644 config/routes.json
rename crossprotocol.html => crossprotocol.template.html (100%)
rename js/{replay-embed.js => replay-embed.template.js} (100%)
diff --git a/.gitignore b/.gitignore
index 4efba1ddbe..a8e9bbcb11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
/index.php
/index.html
/preactalpha.html
+/crossprotocol.html
/data/*
node_modules/
eslint-cache/
@@ -39,6 +40,7 @@ package-lock.json
/js/panel-teambuilder-team.js
/js/panel-teamdropdown.js
/js/panel-battle.js
+/js/replay-embed.js
/replays/caches/
/replays/replay-config.inc.php
diff --git a/action.php b/action.php
index 22e4b0150a..4dc5d90fdf 100644
--- a/action.php
+++ b/action.php
@@ -9,9 +9,11 @@
error_reporting(E_ALL);
+include_once __DIR__ . '/config/config.inc.php';
+
if (@$_GET['act'] === 'dlteam') {
header("Content-Type: text/plain; charset=utf-8");
- if (substr(@$_SERVER['HTTP_REFERER'], 0, 32) !== 'https://play.pokemonshowdown.com') {
+ if (substr(@$_SERVER['HTTP_REFERER'], 0, 32) !== 'https://' . $psconfig['routes']['client']) {
// since this is only to support Chrome on HTTPS, we can get away with a very specific referer check
die("access denied");
}
@@ -26,9 +28,9 @@
}
// header("X-Debug: " . @$_SERVER['HTTP_REFERER']);
-include_once 'lib/ntbb-session.lib.php';
-include_once '../pokemonshowdown.com/config/servers.inc.php';
-include_once 'lib/dispatcher.lib.php';
+require_once __DIR__ . '/lib/ntbb-session.lib.php';
+include_once __DIR__ . '/../pokemonshowdown.com/config/servers.inc.php';
+include_once __DIR__ . '/lib/dispatcher.lib.php';
$dispatcher = new ActionDispatcher(array(
new DefaultActionHandler(),
diff --git a/build-tools/build-indexes b/build-tools/build-indexes
index 4ff25d89d8..e580690410 100755
--- a/build-tools/build-indexes
+++ b/build-tools/build-indexes
@@ -8,18 +8,18 @@ const child_process = require("child_process");
const rootDir = path.resolve(__dirname, '..');
process.chdir(rootDir);
-if (!fs.existsSync('data/Pokemon-Showdown')) {
+if (!fs.existsSync('data/pokemon-showdown')) {
child_process.execSync('git clone https://github.com/smogon/pokemon-showdown.git', {
cwd: 'data',
});
}
process.stdout.write("Syncing data from Git repository... ");
-child_process.execSync('git pull', {cwd: 'data/Pokemon-Showdown'});
-child_process.execSync('npm run build', {cwd: 'data/Pokemon-Showdown'});
+child_process.execSync('git pull', {cwd: 'data/pokemon-showdown'});
+child_process.execSync('npm run build', {cwd: 'data/pokemon-showdown'});
console.log("DONE");
-const Dex = require('../data/Pokemon-Showdown/.sim-dist/dex').Dex;
+const Dex = require('../data/pokemon-showdown/.sim-dist/dex').Dex;
const toID = Dex.getId;
process.stdout.write("Loading gen 6 data... ");
Dex.includeData();
@@ -985,7 +985,7 @@ console.log("DONE");
process.stdout.write("Building `data/pokedex.js`... ");
{
- const Pokedex = requireNoCache('../data/Pokemon-Showdown/.data-dist/pokedex.js').BattlePokedex;
+ const Pokedex = requireNoCache('../data/pokemon-showdown/.data-dist/pokedex.js').BattlePokedex;
for (const id in Pokedex) {
const entry = Pokedex[id];
if (Dex.data.FormatsData[id]) {
@@ -1011,7 +1011,7 @@ console.log("DONE");
process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.js`...");
{
- const Movedex = requireNoCache('../data/Pokemon-Showdown/.data-dist/moves.js').BattleMovedex;
+ const Movedex = requireNoCache('../data/pokemon-showdown/.data-dist/moves.js').BattleMovedex;
const buf = 'exports.BattleMovedex = ' + es3stringify(Movedex) + ';';
fs.writeFileSync('data/moves.js', buf);
}
@@ -1021,7 +1021,7 @@ process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.j
*********************************************************/
{
- const Items = requireNoCache('../data/Pokemon-Showdown/.data-dist/items.js').BattleItems;
+ const Items = requireNoCache('../data/pokemon-showdown/.data-dist/items.js').BattleItems;
const buf = 'exports.BattleItems = ' + es3stringify(Items) + ';';
fs.writeFileSync('data/items.js', buf);
}
@@ -1031,7 +1031,7 @@ process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.j
*********************************************************/
{
- const Abilities = requireNoCache('../data/Pokemon-Showdown/.data-dist/abilities.js').BattleAbilities;
+ const Abilities = requireNoCache('../data/pokemon-showdown/.data-dist/abilities.js').BattleAbilities;
const buf = 'exports.BattleAbilities = ' + es3stringify(Abilities) + ';';
fs.writeFileSync('data/abilities.js', buf);
}
@@ -1041,7 +1041,7 @@ process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.j
*********************************************************/
{
- const TypeChart = requireNoCache('../data/Pokemon-Showdown/.data-dist/typechart.js').BattleTypeChart;
+ const TypeChart = requireNoCache('../data/pokemon-showdown/.data-dist/typechart.js').BattleTypeChart;
const buf = 'exports.BattleTypeChart = ' + es3stringify(TypeChart) + ';';
fs.writeFileSync('data/typechart.js', buf);
}
@@ -1051,7 +1051,7 @@ process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.j
*********************************************************/
{
- const Aliases = requireNoCache('../data/Pokemon-Showdown/.data-dist/aliases.js').BattleAliases;
+ const Aliases = requireNoCache('../data/pokemon-showdown/.data-dist/aliases.js').BattleAliases;
const buf = 'exports.BattleAliases = ' + es3stringify(Aliases) + ';';
fs.writeFileSync('data/aliases.js', buf);
}
@@ -1061,7 +1061,7 @@ process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.j
*********************************************************/
{
- const FormatsData = requireNoCache('../data/Pokemon-Showdown/.data-dist/formats-data.js').BattleFormatsData;
+ const FormatsData = requireNoCache('../data/pokemon-showdown/.data-dist/formats-data.js').BattleFormatsData;
const buf = 'exports.BattleFormatsData = ' + es3stringify(FormatsData) + ';';
fs.writeFileSync('data/formats-data.js', buf);
}
@@ -1071,7 +1071,7 @@ process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.j
*********************************************************/
{
- const Formats = requireNoCache('../data/Pokemon-Showdown/.config-dist/formats.js').Formats;
+ const Formats = requireNoCache('../data/pokemon-showdown/.config-dist/formats.js').Formats;
const buf = 'exports.Formats = ' + es3stringify(Formats) + ';';
fs.writeFileSync('data/formats.js', buf);
}
@@ -1081,7 +1081,7 @@ process.stdout.write("Building `data/moves,items,abilities,typechart,learnsets.j
*********************************************************/
{
- const Learnsets = requireNoCache('../data/Pokemon-Showdown/.data-dist/learnsets.js').BattleLearnsets;
+ const Learnsets = requireNoCache('../data/pokemon-showdown/.data-dist/learnsets.js').BattleLearnsets;
const buf = 'exports.BattleLearnsets = ' + es3stringify(Learnsets) + ';';
fs.writeFileSync('data/learnsets.js', buf);
}
diff --git a/build-tools/build-learnsets b/build-tools/build-learnsets
index c6ecc41b31..2fb7fbcc7d 100755
--- a/build-tools/build-learnsets
+++ b/build-tools/build-learnsets
@@ -18,7 +18,7 @@ const thisFile = __filename;
const thisDir = __dirname;
const rootDir = path.resolve(thisDir, '..');
-const Dex = require('../data/Pokemon-Showdown/.sim-dist/dex').Dex;
+const Dex = require('../data/pokemon-showdown/.sim-dist/dex').Dex;
const toID = Dex.getId;
function updateLearnsets(callback) {
diff --git a/build-tools/build-minidex b/build-tools/build-minidex
index 9b9449fac9..c527292235 100755
--- a/build-tools/build-minidex
+++ b/build-tools/build-minidex
@@ -6,7 +6,7 @@ const path = require("path");
process.chdir(path.resolve(__dirname, '..'));
const imageSize = require('image-size');
-const Dex = require('./../data/Pokemon-Showdown/.sim-dist/dex').Dex;
+const Dex = require('./../data/pokemon-showdown/.sim-dist/dex').Dex;
const toID = Dex.getId;
process.stdout.write("Updating animated sprite dimensions... ");
diff --git a/build-tools/update b/build-tools/update
index a92e2e3af4..5cb049cce5 100755
--- a/build-tools/update
+++ b/build-tools/update
@@ -17,6 +17,13 @@ const thisDir = __dirname;
const rootDir = path.resolve(thisDir, '..');
process.chdir(rootDir);
+const AUTOCONFIG_START = '/*** Begin automatically generated configuration ***/';
+const AUTOCONFIG_END = '/*** End automatically generated configuration ***/';
+
+function escapeRegex(string) {
+ return string.replace(/[\/\*\.]/g, '\\$&');
+}
+
/*********************************************************
* Update version number
*********************************************************/
@@ -36,9 +43,27 @@ try {
version += ` (${head.slice(0, 8)}${head !== origin ? `/${origin.slice(0, 8)}` : ''})`;
} catch (e) {}
+const routes = JSON.parse(fs.readFileSync('config/routes.json'));
+const autoconfigRegex = new RegExp(`${escapeRegex(AUTOCONFIG_START)}[^]+${escapeRegex(AUTOCONFIG_END)}`);
+const autoconfig = `${AUTOCONFIG_START}
+Config.version = ${JSON.stringify(version)};
+
+Config.routes = {
+ root: '${routes.root}',
+ client: '${routes.client}',
+ dex: '${routes.dex}',
+ replays: '${routes.replays}',
+ users: '${routes.users}',
+};
+${AUTOCONFIG_END}`;
+
+// remove old automatically generated configuration and add the new one
let configBuf = fs.readFileSync('config/config.js', {encoding: 'utf8'});
-configBuf = configBuf.replace(/\/\* version \*\/[^;\n]*;/, `/* version */ Config.version = ${JSON.stringify(version)};`);
-
+if (autoconfigRegex.test(configBuf)) {
+ configBuf = configBuf.replace(autoconfigRegex, autoconfig);
+} else {
+ configBuf += autoconfig;
+}
fs.writeFileSync('config/config.js', configBuf);
console.log("DONE");
@@ -82,31 +107,50 @@ if (!ignoreGraphics) {
* Update cachebuster and News
*********************************************************/
-function updateIndex() {
- // add hashes to js and css files
- process.stdout.write("Updating hashes... ");
- let indexContents = fs.readFileSync('index.template.html', {encoding: 'utf8'});
- indexContents = indexContents.replace(/(src|href)="\/(.*?)\?[a-z0-9]*?"/g, function (a, b, c) {
- let hash = Math.random(); // just in case creating the hash fails
- try {
- const filename = c.replace('/play.pokemonshowdown.com/', '');
- const fstr = fs.readFileSync(filename, {encoding: 'utf8'});
- hash = crypto.createHash('md5').update(fstr).digest('hex').substr(0, 8);
- } catch (e) {}
+const URL_REGEX = /(src|href)="\/(.*?)(\?[a-z0-9]*?)?"/g;
- return b + '="/' + c + '?' + hash + '"';
- });
- let indexContents2 = fs.readFileSync('preactalpha.template.html', {encoding: 'utf8'});
- indexContents2 = indexContents2.replace(/(src|href)="\/(.*?)\?[a-z0-9]*?"/g, function (a, b, c) {
+function updateURL(a, b, c, d) {
+ c = c.replace('/replay.pokemonshowdown.com/', '/' + routes.replays + '/');
+ c = c.replace('/dex.pokemonshowdown.com/', '/' + routes.dex + '/');
+ c = c.replace('/play.pokemonshowdown.com/', '/' + routes.client + '/');
+ c = c.replace('/pokemonshowdown.com/', '/' + routes.root + '/');
+
+ if (d) {
let hash = Math.random(); // just in case creating the hash fails
try {
- const filename = c.replace('/play.pokemonshowdown.com/', '');
+ const filename = c.replace('/' + routes.client + '/', '');
const fstr = fs.readFileSync(filename, {encoding: 'utf8'});
hash = crypto.createHash('md5').update(fstr).digest('hex').substr(0, 8);
} catch (e) {}
return b + '="/' + c + '?' + hash + '"';
- });
+ } else {
+ return b + '="/' + c + '"';
+ }
+}
+
+function writeFiles(indexContents, preactIndexContents, crossprotocolContents, replayEmbedContents) {
+ process.stdout.write("Writing new HTML files... ");
+ fs.writeFileSync('index.html', indexContents);
+ fs.writeFileSync('preactalpha.html', preactIndexContents);
+ fs.writeFileSync('crossprotocol.html', crossprotocolContents);
+ console.log("DONE");
+ process.stdout.write("Writing replay-embed.js... ");
+ fs.writeFileSync('js/replay-embed.js', replayEmbedContents);
+ console.log("DONE");
+}
+
+function updateFiles() {
+ // add hashes to js and css files and rewrite URLs
+ process.stdout.write("Updating hashes and URLs... ");
+ let indexContents = fs.readFileSync('index.template.html', {encoding: 'utf8'});
+ indexContents = indexContents.replace(URL_REGEX, updateURL);
+ let preactIndexContents = fs.readFileSync('preactalpha.template.html', {encoding: 'utf8'});
+ preactIndexContents = preactIndexContents.replace(URL_REGEX, updateURL);
+ let crossprotocolContents = fs.readFileSync('crossprotocol.template.html', {encoding: 'utf8'});
+ crossprotocolContents = crossprotocolContents.replace(URL_REGEX, updateURL);
+ let replayEmbedContents = fs.readFileSync('js/replay-embed.template.js', {encoding: 'utf8'});
+ replayEmbedContents = replayEmbedContents.replace(/play\.pokemonshowdown\.com/g, routes.client);
console.log("DONE");
// add news, only if it's actually likely to exist
@@ -128,12 +172,11 @@ function updateIndex() {
indexContents = indexContents.replace(//g, newsData[1]);
console.log("DONE");
- process.stdout.write("Writing new `index.html` file... ");
- fs.writeFileSync('index.html', indexContents);
- fs.writeFileSync('preactalpha.html', indexContents2);
- console.log("DONE");
+ writeFiles(indexContents, preactIndexContents, crossprotocolContents, replayEmbedContents);
});
+ } else {
+ writeFiles(indexContents, preactIndexContents, crossprotocolContents, replayEmbedContents);
}
}
-updateIndex();
+updateFiles();
diff --git a/config/config-example.inc.php b/config/config-example.inc.php
index 3c0660c990..408f40e57a 100644
--- a/config/config-example.inc.php
+++ b/config/config-example.inc.php
@@ -2,6 +2,8 @@
mb_internal_encoding('UTF-8');
+$routes = json_decode(file_get_contents(__DIR__ . '/routes.json'), true);
+
$psconfig = [
'sysops' => ['zarel'],
@@ -22,6 +24,9 @@
'prefix' => 'ps_',
'charset' => 'utf8',
+// routes
+ 'routes' => $routes,
+
// CORS requests
'cors' => [
diff --git a/config/config-example.js b/config/config-example.js
index 6d4c58efd6..22aee1d73b 100644
--- a/config/config-example.js
+++ b/config/config-example.js
@@ -117,6 +117,17 @@ Config.whitelist = [
'4cdn\\.org'
];
+// `defaultserver` specifies the server to use when the domain name in the
+// address bar is `Config.routes.client`.
+Config.defaultserver = {
+ id: 'showdown',
+ host: 'sim3.psim.us',
+ port: 443,
+ httpport: 8000,
+ altport: 80,
+ registered: true
+};
+
Config.roomsFirstOpenScript = function () {
};
diff --git a/config/routes.json b/config/routes.json
new file mode 100644
index 0000000000..69553f29a3
--- /dev/null
+++ b/config/routes.json
@@ -0,0 +1,7 @@
+{
+ "root": "pokemonshowdown.com",
+ "client": "play.pokemonshowdown.com",
+ "dex": "dex.pokemonshowdown.com",
+ "replays": "replay.pokemonshowdown.com",
+ "users": "pokemonshowdown.com/users"
+}
diff --git a/crossdomain.php b/crossdomain.php
index c336c0c899..ebc4629950 100644
--- a/crossdomain.php
+++ b/crossdomain.php
@@ -1,12 +1,14 @@
;
var config = ;
var yourOrigin = ;
-var myOrigin = 'https://play.pokemonshowdown.com';
+var myOrigin = 'https://';
function postReply (message) {
if (window.parent.postMessage === postReply) return;
diff --git a/crossprotocol.html b/crossprotocol.template.html
similarity index 100%
rename from crossprotocol.html
rename to crossprotocol.template.html
diff --git a/customcss.php b/customcss.php
index d0c95571e9..e6fc53f205 100644
--- a/customcss.php
+++ b/customcss.php
@@ -2,7 +2,8 @@
ini_set('max_execution_time', 60); // 1 minute
-include '../pokemonshowdown.com/config/servers.inc.php';
+require_once __DIR__ . '/../pokemonshowdown.com/config/servers.inc.php';
+require_once __DIR__ . '/config/config.inc.php';
spl_autoload_register(function ($class) {
require_once('lib/css-sanitizer/'.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php');
@@ -70,11 +71,11 @@
// Parse a stylesheet from a string
$parser = Parser::newFromString($curlret);
$stylesheet = $parser->parseStylesheet();
-
+
// Apply sanitization to the stylehseet
$sanitizer = StylesheetSanitizer::newDefault();
$newStylesheet = $sanitizer->sanitize( $stylesheet );
-
+
// Convert the sanitized stylesheet back to text
$outputcss = Wikimedia\CSS\Util::stringify( $newStylesheet, [ 'minify' => true ] );
@@ -98,7 +99,7 @@
Done: = htmlspecialchars($customcssuri) ?> was reloaded.
- Back to server management
+ Back to server management
-
+
@@ -115,7 +115,6 @@