Compare commits
8 Commits
088e64f37d
...
main
Author | SHA1 | Date | |
---|---|---|---|
4f7e9ff3d8
|
|||
c5eeb3c911
|
|||
5aff5e9277
|
|||
54b3588c3a
|
|||
16f954f1e5
|
|||
![]() |
f7db6ba295
|
||
![]() |
8bea7758f0
|
||
![]() |
b794dcbcd3
|
33
.gitignore
vendored
33
.gitignore
vendored
@@ -1,28 +1,5 @@
|
|||||||
lib/test.html
|
/compose.yml
|
||||||
lib/postdata.json
|
/docker-compose.yml
|
||||||
lib/nextpage.json
|
/banner
|
||||||
scraper/brave.html
|
/favicon.ico
|
||||||
scraper/yandex.json
|
/config.php
|
||||||
scraper/marginalia.json
|
|
||||||
banner_og/
|
|
||||||
scraper/mojeek.html
|
|
||||||
scraper/google.html
|
|
||||||
scraper/google-img.html
|
|
||||||
scraper/google-video.html
|
|
||||||
scraper/google-news.html
|
|
||||||
scraper/google-img-nextpage.html
|
|
||||||
scraper/brave-image.html
|
|
||||||
scraper/brave-video.html
|
|
||||||
scraper/facebook.html
|
|
||||||
scraper/facebook-nextpage.json
|
|
||||||
scraper/yandex-video.json
|
|
||||||
scraper/yandex.html
|
|
||||||
scraper/soundcloud.json
|
|
||||||
scraper/mp3-pm.html
|
|
||||||
banner/*
|
|
||||||
data/captcha/birds/
|
|
||||||
data/captcha/fumo_plushies/
|
|
||||||
data/captcha/minecraft/
|
|
||||||
!banner/*default*
|
|
||||||
scraper/curlie.html
|
|
||||||
icons/*
|
|
||||||
|
28
Dockerfile
28
Dockerfile
@@ -1,24 +1,20 @@
|
|||||||
FROM alpine:latest
|
FROM alpine
|
||||||
|
|
||||||
RUN apk update
|
RUN apk update && \
|
||||||
RUN apk upgrade
|
apk upgrade && \
|
||||||
|
apk add \
|
||||||
RUN apk add php apache2-ssl php83-fileinfo php83-openssl \
|
php php83-fileinfo php83-iconv php83-common php83-dom php83-sodium \
|
||||||
php83-iconv php83-common php83-dom php83-sodium \
|
php83-curl php83-pecl-apcu php83-apache2 php-mbstring \
|
||||||
php83-curl curl php83-pecl-apcu php83-apache2 \
|
php83-pecl-imagick imagemagick-webp imagemagick-jpeg
|
||||||
imagemagick php83-pecl-imagick php-mbstring \
|
|
||||||
imagemagick-webp imagemagick-jpeg
|
|
||||||
|
|
||||||
COPY ./docker/httpd.conf /etc/apache2/httpd.conf
|
COPY ./docker/httpd.conf /etc/apache2/httpd.conf
|
||||||
COPY ./docker/init.sh /
|
COPY ./docker/init.sh /
|
||||||
|
|
||||||
WORKDIR /var/www/html
|
WORKDIR /srv
|
||||||
COPY ./src ./4get
|
COPY ./src ./4get
|
||||||
|
|
||||||
WORKDIR /var/www/html/4get
|
RUN adduser -DSH -u 1000 -h /srv runner
|
||||||
COPY ./docker/gen_config.php .
|
RUN chown -R runner /srv && chmod +x /init.sh
|
||||||
|
|
||||||
RUN chmod 777 /var/www/html/4get/icons
|
USER runner
|
||||||
RUN chmod +x /init.sh
|
CMD ["/init.sh"]
|
||||||
|
|
||||||
CMD ["/init.sh"]
|
|
||||||
|
18
compose.example.yml
Normal file
18
compose.example.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
fourget:
|
||||||
|
container_name: 4get
|
||||||
|
image: git.ngn.tf/ngn/4get
|
||||||
|
ports:
|
||||||
|
- 80:8080
|
||||||
|
volumes:
|
||||||
|
- ./config.php:/srv/4get/data/config.php:ro
|
||||||
|
- ./favicon.ico:/srv/4get/favicon.ico:ro
|
||||||
|
- ./banner:/srv/4get/banner:ro
|
||||||
|
- type: tmpfs
|
||||||
|
target: /tmp/icons
|
||||||
|
cap_drop:
|
||||||
|
- ALL
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
|
read_only: true
|
||||||
|
restart: unless-stopped
|
@@ -1,12 +0,0 @@
|
|||||||
services:
|
|
||||||
fourget:
|
|
||||||
container_name: 4get
|
|
||||||
image: git.ngn.tf/ngn/4get
|
|
||||||
environment:
|
|
||||||
- FOURGET_SERVER_NAME=example.com
|
|
||||||
ports:
|
|
||||||
- 80:80
|
|
||||||
volumes:
|
|
||||||
- ./banners:/var/www/html/4get/banner
|
|
||||||
- ./captcha:/var/www/html/4get/data/captcha
|
|
||||||
restart: unless-stopped
|
|
@@ -1,90 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
include "/var/www/html/4get/data/config.php";
|
|
||||||
|
|
||||||
$refl = new ReflectionClass('config');
|
|
||||||
$from_config = ($refl->getConstants());
|
|
||||||
$from_env = array();
|
|
||||||
|
|
||||||
$env = getenv();
|
|
||||||
$fourget_env = array_filter($env, function($v, $k) {
|
|
||||||
return str_starts_with($k, "FOURGET");
|
|
||||||
}, ARRAY_FILTER_USE_BOTH);
|
|
||||||
|
|
||||||
foreach($fourget_env as $key => $val) {
|
|
||||||
$target_key = preg_replace('/^FOURGET_/', '', $key);
|
|
||||||
$from_env[$target_key] = trim($val, '\'"');
|
|
||||||
};
|
|
||||||
|
|
||||||
$merged_config = array_merge($from_config, $from_env);
|
|
||||||
|
|
||||||
function type_to_string($n) {
|
|
||||||
$type = gettype($n);
|
|
||||||
if ($type === "NULL") {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
if ($type === "boolean") {
|
|
||||||
return $n ? 'true' : 'false';
|
|
||||||
}
|
|
||||||
if ($type === "string") {
|
|
||||||
if(is_numeric($n)) {
|
|
||||||
return $n;
|
|
||||||
}
|
|
||||||
return "\"$n\"";
|
|
||||||
}
|
|
||||||
if ($type === "array") {
|
|
||||||
return json_encode($n, JSON_UNESCAPED_SLASHES);
|
|
||||||
}
|
|
||||||
return $n;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function detect_captcha_dirs() {
|
|
||||||
$captcha_dir = "/var/www/html/4get/data/captcha/";
|
|
||||||
$categories = (array_map(function ($n) {
|
|
||||||
return explode("/", $n)[7];
|
|
||||||
}, glob($captcha_dir . "*")));
|
|
||||||
|
|
||||||
|
|
||||||
$result = array_map(function($category) {
|
|
||||||
return [$category, count(glob("/var/www/html/4get/data/captcha/" . $category . "/*" ))];
|
|
||||||
}, $categories);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$special_keys = ["PROTO", "CAPTCHA_DATASET"];
|
|
||||||
|
|
||||||
$output = "<?php\n // This file was generated by docker/gen_config.php\n";
|
|
||||||
|
|
||||||
$output = $output . "class config {\n";
|
|
||||||
foreach(($merged_config) as $key => $val){
|
|
||||||
if(!in_array($key, $special_keys)) {
|
|
||||||
$stored_value = $val;
|
|
||||||
// conversion between arrays and comma separated env value.
|
|
||||||
// Handle case when original type of field is array and there is a type mismatch when a comma separted string is passed,
|
|
||||||
// then split on comma if string (and not numeric, boolean, null, etc)
|
|
||||||
//
|
|
||||||
// except in the case where the inital value in default config is null or boolean. Assuming null and boolean
|
|
||||||
// in default config will be never be assigned an array
|
|
||||||
|
|
||||||
if(gettype($from_config[$key]) != gettype($val) && !is_numeric($val) && !is_null($from_config[$key]) && gettype($from_config[$key]) != "boolean") {
|
|
||||||
$stored_value = explode(",", $val);
|
|
||||||
}
|
|
||||||
$output = $output . "\tconst " . $key . " = " . type_to_string($stored_value) . ";\n";
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if($key === "CAPTCHA_DATASET") {
|
|
||||||
$output = $output . "\tconst " . $key . " = " . type_to_string(detect_captcha_dirs()) . ";\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$output = $output . "}\n";
|
|
||||||
$output = $output . "?>";
|
|
||||||
|
|
||||||
file_put_contents("./data/config.php", $output);
|
|
||||||
?>
|
|
@@ -1,16 +1,19 @@
|
|||||||
Listen 80
|
Listen 8080
|
||||||
ServerTokens OS
|
|
||||||
ServerRoot /var/www
|
ServerRoot /var/www
|
||||||
ServerSignature On
|
|
||||||
ServerName localhost
|
ServerName localhost
|
||||||
|
|
||||||
DocumentRoot "/var/www/html/4get"
|
ServerSignature Off
|
||||||
|
ServerTokens Prod
|
||||||
|
|
||||||
LogLevel error
|
PidFile /dev/shm/httpd.pid
|
||||||
|
DocumentRoot /srv/4get
|
||||||
|
|
||||||
|
LogLevel error
|
||||||
CustomLog /dev/null common
|
CustomLog /dev/null common
|
||||||
ErrorLog /dev/null
|
ErrorLog /dev/stderr
|
||||||
|
|
||||||
<Directory "/var/www/html/4get">
|
<Directory /srv/4get>
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
RewriteCond %{THE_REQUEST} ^\w+\ /(.*)\.php(\?.*)?\ HTTP/
|
RewriteCond %{THE_REQUEST} ^\w+\ /(.*)\.php(\?.*)?\ HTTP/
|
||||||
RewriteRule ^ http://%{HTTP_HOST}/%1 [R=301]
|
RewriteRule ^ http://%{HTTP_HOST}/%1 [R=301]
|
||||||
@@ -22,68 +25,32 @@ ErrorLog /dev/null
|
|||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
# deny access to private resources
|
# deny access to private resources
|
||||||
<Directory "/var/www/html/4get/data">
|
<Directory /srv/4get/data>
|
||||||
Require all denied
|
Require all denied
|
||||||
<Files "*">
|
<Files *>
|
||||||
Require all denied
|
Require all denied
|
||||||
</Files>
|
</Files>
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
LoadModule rewrite_module modules/mod_rewrite.so
|
LoadModule rewrite_module modules/mod_rewrite.so
|
||||||
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
|
LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
|
||||||
LoadModule authn_file_module modules/mod_authn_file.so
|
LoadModule authz_core_module modules/mod_authz_core.so
|
||||||
LoadModule authn_core_module modules/mod_authn_core.so
|
|
||||||
LoadModule authz_host_module modules/mod_authz_host.so
|
|
||||||
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
|
|
||||||
LoadModule authz_user_module modules/mod_authz_user.so
|
|
||||||
LoadModule authz_core_module modules/mod_authz_core.so
|
|
||||||
LoadModule access_compat_module modules/mod_access_compat.so
|
LoadModule access_compat_module modules/mod_access_compat.so
|
||||||
LoadModule auth_basic_module modules/mod_auth_basic.so
|
LoadModule filter_module modules/mod_filter.so
|
||||||
LoadModule reqtimeout_module modules/mod_reqtimeout.so
|
LoadModule mime_module modules/mod_mime.so
|
||||||
LoadModule filter_module modules/mod_filter.so
|
LoadModule log_config_module modules/mod_log_config.so
|
||||||
LoadModule mime_module modules/mod_mime.so
|
LoadModule unixd_module modules/mod_unixd.so
|
||||||
LoadModule log_config_module modules/mod_log_config.so
|
LoadModule negotiation_module modules/mod_negotiation.so
|
||||||
LoadModule env_module modules/mod_env.so
|
LoadModule dir_module modules/mod_dir.so
|
||||||
LoadModule headers_module modules/mod_headers.so
|
|
||||||
LoadModule setenvif_module modules/mod_setenvif.so
|
|
||||||
LoadModule version_module modules/mod_version.so
|
|
||||||
LoadModule unixd_module modules/mod_unixd.so
|
|
||||||
LoadModule status_module modules/mod_status.so
|
|
||||||
LoadModule autoindex_module modules/mod_autoindex.so
|
|
||||||
LoadModule dir_module modules/mod_dir.so
|
|
||||||
LoadModule alias_module modules/mod_alias.so
|
|
||||||
LoadModule negotiation_module modules/mod_negotiation.so
|
|
||||||
|
|
||||||
<IfModule unixd_module>
|
|
||||||
User apache
|
|
||||||
Group apache
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<Directory />
|
<Directory />
|
||||||
AllowOverride none
|
AllowOverride none
|
||||||
Require all denied
|
Require all denied
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<IfModule dir_module>
|
|
||||||
DirectoryIndex index.html
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<Files ".ht*">
|
<Files ".ht*">
|
||||||
Require all denied
|
Require all denied
|
||||||
</Files>
|
</Files>
|
||||||
|
|
||||||
<IfModule headers_module>
|
Include /etc/apache2/conf.d/languages.conf
|
||||||
RequestHeader unset Proxy early
|
Include /etc/apache2/conf.d/php83-module.conf
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mime_module>
|
|
||||||
TypesConfig /etc/apache2/mime.types
|
|
||||||
AddType application/x-compress .Z
|
|
||||||
AddType application/x-gzip .gz .tgz
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
<IfModule mime_magic_module>
|
|
||||||
MIMEMagicFile /etc/apache2/magic
|
|
||||||
</IfModule>
|
|
||||||
|
|
||||||
IncludeOptional /etc/apache2/conf.d/*.conf
|
|
||||||
|
@@ -1,11 +1,17 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh -e
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ ! -f '/var/www/html/4get/data/config.php' ] && [ -f './gen_config.php' ]
|
config='/srv/4get/data/config.php'
|
||||||
then
|
defconfig='/srv/4get/data/config.def.php'
|
||||||
php ./gen_config.php
|
|
||||||
rm -f ./gen_config.php
|
# check for the configuration file
|
||||||
|
if [ ! -f "${config}" ]; then
|
||||||
|
echo "configuration file not specified"
|
||||||
|
echo "here's the default configuration, modify and mount this to ${config}"
|
||||||
|
echo
|
||||||
|
cat "${defconfig}"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Starting up apache2"
|
# execute apache
|
||||||
exec httpd -DFOREGROUND
|
echo "starting apache web server"
|
||||||
|
exec httpd -D FOREGROUND
|
||||||
|
28
src/.gitignore
vendored
Normal file
28
src/.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
lib/test.html
|
||||||
|
lib/postdata.json
|
||||||
|
lib/nextpage.json
|
||||||
|
|
||||||
|
scraper/brave.html
|
||||||
|
scraper/yandex.json
|
||||||
|
scraper/marginalia.json
|
||||||
|
scraper/mojeek.html
|
||||||
|
scraper/google.html
|
||||||
|
scraper/google-img.html
|
||||||
|
scraper/google-video.html
|
||||||
|
scraper/google-news.html
|
||||||
|
scraper/google-img-nextpage.html
|
||||||
|
scraper/brave-image.html
|
||||||
|
scraper/brave-video.html
|
||||||
|
scraper/facebook.html
|
||||||
|
scraper/facebook-nextpage.json
|
||||||
|
scraper/yandex-video.json
|
||||||
|
scraper/yandex.html
|
||||||
|
scraper/soundcloud.json
|
||||||
|
scraper/mp3-pm.html
|
||||||
|
scraper/curlie.html
|
||||||
|
|
||||||
|
banner/*
|
||||||
|
data/*
|
||||||
|
|
||||||
|
!banner/*default*
|
||||||
|
!data/*.def.*
|
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
include "data/config.php";
|
|
||||||
include "lib/frontend.php";
|
|
||||||
$frontend = new frontend();
|
|
||||||
|
|
||||||
echo
|
|
||||||
$frontend->load(
|
|
||||||
"header_nofilters.html",
|
|
||||||
[
|
|
||||||
"title" => "About",
|
|
||||||
"class" => " class=\"about\""
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
$left =
|
|
||||||
explode(
|
|
||||||
"\n",
|
|
||||||
file_get_contents("template/about.html")
|
|
||||||
);
|
|
||||||
|
|
||||||
$out = "";
|
|
||||||
|
|
||||||
foreach($left as $line){
|
|
||||||
|
|
||||||
$out .= trim($line);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo
|
|
||||||
$frontend->load(
|
|
||||||
"search.html",
|
|
||||||
[
|
|
||||||
"timetaken" => null,
|
|
||||||
"class" => "",
|
|
||||||
"right-left" => "",
|
|
||||||
"right-right" => "",
|
|
||||||
"left" => $out
|
|
||||||
]
|
|
||||||
);
|
|
87
src/data/config.def.php
Normal file
87
src/data/config.def.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
class config{
|
||||||
|
// Welcome to the 4get configuration file
|
||||||
|
// When updating your instance, please make sure this file isn't missing
|
||||||
|
// any parameters.
|
||||||
|
|
||||||
|
// 4get version. Please keep this updated
|
||||||
|
const VERSION = 8;
|
||||||
|
|
||||||
|
// Will be shown pretty much everywhere.
|
||||||
|
const SERVER_NAME = "4get";
|
||||||
|
|
||||||
|
// Will be shown in <meta> tag on home page
|
||||||
|
const SERVER_SHORT_DESCRIPTION = "4get is a proxy search engine that doesn't suck.";
|
||||||
|
|
||||||
|
// Will be shown in server list ping (null for no description)
|
||||||
|
const SERVER_LONG_DESCRIPTION = null;
|
||||||
|
|
||||||
|
// Add your own themes in "static/themes". Set to "Dark" for default theme.
|
||||||
|
// Eg. To use "static/themes/Cream.css", specify "Cream".
|
||||||
|
const DEFAULT_THEME = "black";
|
||||||
|
|
||||||
|
// Default user agent to use for scraper requests. Sometimes ignored to get specific webpages
|
||||||
|
// Changing this might break things.
|
||||||
|
const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0";
|
||||||
|
|
||||||
|
// Temporary directory for saving the page icons
|
||||||
|
const ICON_DIR = "/tmp/icons";
|
||||||
|
|
||||||
|
// List of domains that point to your servers. Include your tor/i2p
|
||||||
|
// addresses here! Must be a valid URL. Won't affect links placed on
|
||||||
|
// the homepage.
|
||||||
|
const ALT_ADDRESSES = [
|
||||||
|
//"https://4get.alt-tld",
|
||||||
|
//"http://4getwebfrq5zr4sxugk6htxvawqehxtdgjrbcn2oslllcol2vepa23yd.onion"
|
||||||
|
];
|
||||||
|
|
||||||
|
// Proxy pool assignments for each scraper
|
||||||
|
// false = Use server's raw IP
|
||||||
|
// string = will load a proxy list from data directory
|
||||||
|
// Eg. "tor" will load data/tor.txt
|
||||||
|
const PROXY_DDG = false; // duckduckgo
|
||||||
|
const PROXY_BRAVE = false;
|
||||||
|
const PROXY_FB = false; // facebook
|
||||||
|
const PROXY_GOOGLE = false;
|
||||||
|
const PROXY_GOOGLE_API = false;
|
||||||
|
const PROXY_GOOGLE_CSE = false;
|
||||||
|
const PROXY_STARTPAGE = false;
|
||||||
|
const PROXY_QWANT = false;
|
||||||
|
const PROXY_GHOSTERY = false;
|
||||||
|
const PROXY_MARGINALIA = false;
|
||||||
|
const PROXY_MOJEEK = false;
|
||||||
|
const PROXY_SC = false; // soundcloud
|
||||||
|
const PROXY_SPOTIFY = false;
|
||||||
|
const PROXY_SOLOFIELD = false;
|
||||||
|
const PROXY_WIBY = false;
|
||||||
|
const PROXY_CURLIE = false;
|
||||||
|
const PROXY_YT = false; // youtube
|
||||||
|
const PROXY_YEP = false;
|
||||||
|
const PROXY_PINTEREST = false;
|
||||||
|
const PROXY_SANKAKUCOMPLEX = false;
|
||||||
|
const PROXY_FLICKR = false;
|
||||||
|
const PROXY_FIVEHPX = false;
|
||||||
|
const PROXY_VSCO = false;
|
||||||
|
const PROXY_SEZNAM = false;
|
||||||
|
const PROXY_NAVER = false;
|
||||||
|
const PROXY_GREPPR = false;
|
||||||
|
const PROXY_CROWDVIEW = false;
|
||||||
|
const PROXY_MWMBL = false;
|
||||||
|
const PROXY_FTM = false; // findthatmeme
|
||||||
|
const PROXY_IMGUR = false;
|
||||||
|
const PROXY_YANDEX_W = false; // yandex web
|
||||||
|
const PROXY_YANDEX_I = false; // yandex images
|
||||||
|
const PROXY_YANDEX_V = false; // yandex videos
|
||||||
|
|
||||||
|
//
|
||||||
|
// Scraper-specific parameters
|
||||||
|
//
|
||||||
|
|
||||||
|
// GOOGLE CSE & GOOGLE API
|
||||||
|
const GOOGLE_CX_ENDPOINT = "d4e68b99b876541f0";
|
||||||
|
|
||||||
|
// MARGINALIA
|
||||||
|
// Use "null" to default out to HTML scraping OR specify a string to
|
||||||
|
// use the API (Eg: "public"). API has less filters.
|
||||||
|
const MARGINALIA_API_KEY = null;
|
||||||
|
}
|
@@ -1,173 +0,0 @@
|
|||||||
<?php
|
|
||||||
class config{
|
|
||||||
// Welcome to the 4get configuration file
|
|
||||||
// When updating your instance, please make sure this file isn't missing
|
|
||||||
// any parameters.
|
|
||||||
|
|
||||||
// 4get version. Please keep this updated
|
|
||||||
const VERSION = 8;
|
|
||||||
|
|
||||||
// Will be shown pretty much everywhere.
|
|
||||||
const SERVER_NAME = "4get";
|
|
||||||
|
|
||||||
// Will be shown in <meta> tag on home page
|
|
||||||
const SERVER_SHORT_DESCRIPTION = "4get is a proxy search engine that doesn't suck.";
|
|
||||||
|
|
||||||
// Will be shown in server list ping (null for no description)
|
|
||||||
const SERVER_LONG_DESCRIPTION = null;
|
|
||||||
|
|
||||||
// Add your own themes in "static/themes". Set to "Dark" for default theme.
|
|
||||||
// Eg. To use "static/themes/Cream.css", specify "Cream".
|
|
||||||
const DEFAULT_THEME = "black";
|
|
||||||
|
|
||||||
// Enable the API?
|
|
||||||
const API_ENABLED = true;
|
|
||||||
|
|
||||||
//
|
|
||||||
// BOT PROTECTION
|
|
||||||
//
|
|
||||||
|
|
||||||
// 0 = disabled, 1 = ask for image captcha, @TODO: 2 = invite only (users needs a pass)
|
|
||||||
// VERY useful against a targetted attack
|
|
||||||
const BOT_PROTECTION = 0;
|
|
||||||
|
|
||||||
// if BOT_PROTECTION is set to 1, specify the available datasets here
|
|
||||||
// images should be named from 1.png to X.png, and be 100x100 in size
|
|
||||||
// Eg. data/captcha/birds/1.png up to 2263.png
|
|
||||||
const CAPTCHA_DATASET = [
|
|
||||||
// example:
|
|
||||||
//["birds", 2263],
|
|
||||||
//["fumo_plushies", 1006],
|
|
||||||
//["minecraft", 848]
|
|
||||||
];
|
|
||||||
|
|
||||||
// If this regex expression matches on the user agent, it blocks the request
|
|
||||||
// Not useful at all against a targetted attack
|
|
||||||
const HEADER_REGEX = '/bot|wget|curl|python-requests|scrapy|go-http-client|ruby|yahoo|spider|qwant/i';
|
|
||||||
|
|
||||||
// Block clients who present any of the following headers in their request (SPECIFY IN !!lowercase!!)
|
|
||||||
// Eg: ["x-forwarded-for", "x-via", "forwarded-for", "via"];
|
|
||||||
// Useful for blocking *some* proxies used for botting
|
|
||||||
const FILTERED_HEADER_KEYS = [
|
|
||||||
//"x-forwarded-for",
|
|
||||||
//"x-cluster-client-ip",
|
|
||||||
//"x-client-ip",
|
|
||||||
//"x-real-ip",
|
|
||||||
//"client-ip",
|
|
||||||
//"real-ip",
|
|
||||||
//"forwarded-for",
|
|
||||||
//"forwarded-for-ip",
|
|
||||||
//"forwarded",
|
|
||||||
//"proxy-connection",
|
|
||||||
//"remote-addr",
|
|
||||||
//"via"
|
|
||||||
];
|
|
||||||
|
|
||||||
// Block SSL ciphers used by CLI tools used for botting
|
|
||||||
// Basically a primitive version of Cloudflare's browser integrity check
|
|
||||||
// ** If curl can still access the site (with spoofed headers), please make sure you use the new apache2 config **
|
|
||||||
// https://git.lolcat.ca/lolcat/4get/docs/apache2.md
|
|
||||||
const DISALLOWED_SSL = [
|
|
||||||
// "TLS_AES_256_GCM_SHA384" // used by WGET and CURL
|
|
||||||
];
|
|
||||||
|
|
||||||
// Maximal number of searches per captcha key/pass issued. Counter gets
|
|
||||||
// reset on every APCU cache clear (should happen once a day).
|
|
||||||
// Only useful when BOT_PROTECTION is NOT set to 0
|
|
||||||
const MAX_SEARCHES = 100;
|
|
||||||
|
|
||||||
// List of domains that point to your servers. Include your tor/i2p
|
|
||||||
// addresses here! Must be a valid URL. Won't affect links placed on
|
|
||||||
// the homepage.
|
|
||||||
const ALT_ADDRESSES = [
|
|
||||||
//"https://4get.alt-tld",
|
|
||||||
//"http://4getwebfrq5zr4sxugk6htxvawqehxtdgjrbcn2oslllcol2vepa23yd.onion"
|
|
||||||
];
|
|
||||||
|
|
||||||
// Known 4get instances. MUST use the https protocol if your instance uses
|
|
||||||
// it. Is used to generate a distributed list of instances.
|
|
||||||
// To appear in the list of an instance, contact the host and if everyone added
|
|
||||||
// eachother your serber should appear everywhere.
|
|
||||||
const INSTANCES = [
|
|
||||||
"https://4get.ca",
|
|
||||||
"https://4get.zzls.xyz",
|
|
||||||
"https://4getus.zzls.xyz",
|
|
||||||
"https://4get.silly.computer",
|
|
||||||
"https://4get.konakona.moe",
|
|
||||||
"https://4get.lvkaszus.pl",
|
|
||||||
"https://4g.ggtyler.dev",
|
|
||||||
"https://4get.perennialte.ch",
|
|
||||||
"https://4get.sijh.net",
|
|
||||||
"https://4get.hbubli.cc",
|
|
||||||
"https://4get.plunked.party",
|
|
||||||
"https://4get.seitan-ayoub.lol",
|
|
||||||
"https://4get.etenie.pl",
|
|
||||||
"https://4get.lunar.icu",
|
|
||||||
"https://4get.dcs0.hu",
|
|
||||||
"https://4get.kizuki.lol",
|
|
||||||
"https://4get.psily.garden",
|
|
||||||
"https://search.milivojevic.in.rs",
|
|
||||||
"https://4get.snine.nl",
|
|
||||||
"https://4get.datura.network",
|
|
||||||
"https://4get.neco.lol",
|
|
||||||
"https://4get.lol",
|
|
||||||
"https://4get.ch",
|
|
||||||
"https://4get.edmateo.site",
|
|
||||||
"https://4get.sudovanilla.org",
|
|
||||||
"https://search.mint.lgbt"
|
|
||||||
];
|
|
||||||
|
|
||||||
// Default user agent to use for scraper requests. Sometimes ignored to get specific webpages
|
|
||||||
// Changing this might break things.
|
|
||||||
const USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0";
|
|
||||||
|
|
||||||
// Proxy pool assignments for each scraper
|
|
||||||
// false = Use server's raw IP
|
|
||||||
// string = will load a proxy list from data/proxies
|
|
||||||
// Eg. "onion" will load data/proxies/onion.txt
|
|
||||||
const PROXY_DDG = false; // duckduckgo
|
|
||||||
const PROXY_BRAVE = false;
|
|
||||||
const PROXY_FB = false; // facebook
|
|
||||||
const PROXY_GOOGLE = false;
|
|
||||||
const PROXY_GOOGLE_API = false;
|
|
||||||
const PROXY_GOOGLE_CSE = false;
|
|
||||||
const PROXY_STARTPAGE = false;
|
|
||||||
const PROXY_QWANT = false;
|
|
||||||
const PROXY_GHOSTERY = false;
|
|
||||||
const PROXY_MARGINALIA = false;
|
|
||||||
const PROXY_MOJEEK = false;
|
|
||||||
const PROXY_SC = false; // soundcloud
|
|
||||||
const PROXY_SPOTIFY = false;
|
|
||||||
const PROXY_SOLOFIELD = false;
|
|
||||||
const PROXY_WIBY = false;
|
|
||||||
const PROXY_CURLIE = false;
|
|
||||||
const PROXY_YT = false; // youtube
|
|
||||||
const PROXY_YEP = false;
|
|
||||||
const PROXY_PINTEREST = false;
|
|
||||||
const PROXY_SANKAKUCOMPLEX = false;
|
|
||||||
const PROXY_FLICKR = false;
|
|
||||||
const PROXY_FIVEHPX = false;
|
|
||||||
const PROXY_VSCO = false;
|
|
||||||
const PROXY_SEZNAM = false;
|
|
||||||
const PROXY_NAVER = false;
|
|
||||||
const PROXY_GREPPR = false;
|
|
||||||
const PROXY_CROWDVIEW = false;
|
|
||||||
const PROXY_MWMBL = false;
|
|
||||||
const PROXY_FTM = false; // findthatmeme
|
|
||||||
const PROXY_IMGUR = false;
|
|
||||||
const PROXY_YANDEX_W = false; // yandex web
|
|
||||||
const PROXY_YANDEX_I = false; // yandex images
|
|
||||||
const PROXY_YANDEX_V = false; // yandex videos
|
|
||||||
|
|
||||||
//
|
|
||||||
// Scraper-specific parameters
|
|
||||||
//
|
|
||||||
|
|
||||||
// GOOGLE CSE & GOOGLE API
|
|
||||||
const GOOGLE_CX_ENDPOINT = "d4e68b99b876541f0";
|
|
||||||
|
|
||||||
// MARGINALIA
|
|
||||||
// Use "null" to default out to HTML scraping OR specify a string to
|
|
||||||
// use the API (Eg: "public"). API has less filters.
|
|
||||||
const MARGINALIA_API_KEY = null;
|
|
||||||
}
|
|
Binary file not shown.
3
src/data/proxies/.gitignore
vendored
3
src/data/proxies/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
!onion.txt
|
|
@@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
include "data/config.php";
|
|
||||||
include "lib/frontend.php";
|
|
||||||
$frontend = new frontend();
|
|
||||||
|
|
||||||
echo
|
|
||||||
$frontend->load(
|
|
||||||
"header_nofilters.html",
|
|
||||||
[
|
|
||||||
"title" => "Donate to the project",
|
|
||||||
"class" => " class=\"about\""
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
$left =
|
|
||||||
explode(
|
|
||||||
"\n",
|
|
||||||
file_get_contents("template/donate.html")
|
|
||||||
);
|
|
||||||
|
|
||||||
$out = "";
|
|
||||||
|
|
||||||
foreach($left as $line){
|
|
||||||
|
|
||||||
$out .= trim($line);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo
|
|
||||||
$frontend->load(
|
|
||||||
"search.html",
|
|
||||||
[
|
|
||||||
"timetaken" => null,
|
|
||||||
"class" => "",
|
|
||||||
"right-left" => "",
|
|
||||||
"right-right" => "",
|
|
||||||
"left" => $out
|
|
||||||
]
|
|
||||||
);
|
|
213
src/favicon.php
213
src/favicon.php
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
if(!isset($_GET["s"])){
|
if(!isset($_GET["s"])){
|
||||||
|
|
||||||
header("X-Error: Missing parameter (s)ite");
|
header("X-Error: Missing parameter (s)ite");
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
@@ -10,86 +10,92 @@ include "data/config.php";
|
|||||||
new favicon($_GET["s"]);
|
new favicon($_GET["s"]);
|
||||||
|
|
||||||
class favicon{
|
class favicon{
|
||||||
|
|
||||||
public function __construct($url){
|
public function __construct($url){
|
||||||
|
|
||||||
header("Content-Type: image/png");
|
header("Content-Type: image/png");
|
||||||
|
|
||||||
if(
|
// first check the URL with regex
|
||||||
preg_match(
|
if(preg_match('/^https?:\/\/[A-Za-z0-9.-]+$/', $url) === 0){
|
||||||
'/^https?:\/\/[A-Za-z0-9.-]+$/',
|
|
||||||
$url
|
|
||||||
) === 0
|
|
||||||
){
|
|
||||||
|
|
||||||
header("X-Error: Only provide the protocol and domain");
|
header("X-Error: Only provide the protocol and domain");
|
||||||
$this->defaulticon();
|
$this->defaulticon();
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = str_replace(["https://", "http://"], "", $url);
|
// validate the URL
|
||||||
header("Content-Disposition: inline; filename=\"{$filename}.png\"");
|
$url = filter_var($url, FILTER_VALIDATE_URL);
|
||||||
|
if(!$url) {
|
||||||
|
header("X-Error: Invalid URL");
|
||||||
|
$this->defaulticon();
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the hostname
|
||||||
|
$this->filename = parse_url($url, PHP_URL_HOST);
|
||||||
|
if(!$this->filename || is_null($this->filename) || $this->filename === ""){
|
||||||
|
header("X-Error: Invalid URL");
|
||||||
|
$this->defaulticon();
|
||||||
|
}
|
||||||
|
|
||||||
|
// specify the filename in content-disposition
|
||||||
|
header("Content-Disposition: inline; filename=\"{$this->filename}.png\"");
|
||||||
|
|
||||||
include "lib/curlproxy.php";
|
include "lib/curlproxy.php";
|
||||||
$this->proxy = new proxy(false);
|
$this->proxy = new proxy(false);
|
||||||
|
|
||||||
$this->filename = parse_url($url, PHP_URL_HOST);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if we have the favicon stored locally
|
Check if we have the favicon stored locally
|
||||||
*/
|
*/
|
||||||
if(file_exists("icons/" . $filename . ".png")){
|
if(file_exists($this->iconpath())){
|
||||||
|
$handle = fopen($this->iconpath(), "r");
|
||||||
$handle = fopen("icons/" . $filename . ".png", "r");
|
echo fread($handle, filesize($this->iconpath()));
|
||||||
echo fread($handle, filesize("icons/" . $filename . ".png"));
|
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Scrape html
|
Scrape html
|
||||||
*/
|
*/
|
||||||
try{
|
try{
|
||||||
|
|
||||||
$payload = $this->proxy->get($url, $this->proxy::req_web, true);
|
$payload = $this->proxy->get($url, $this->proxy::req_web, true);
|
||||||
|
|
||||||
}catch(Exception $error){
|
}catch(Exception $error){
|
||||||
|
|
||||||
header("X-Error: Could not fetch HTML (" . $error->getMessage() . ")");
|
header("X-Error: Could not fetch HTML (" . $error->getMessage() . ")");
|
||||||
$this->favicon404();
|
$this->favicon404();
|
||||||
}
|
}
|
||||||
//$payload["body"] = '<link rel="manifest" id="MANIFEST_LINK" href="/data/manifest/" crossorigin="use-credentials" />';
|
//$payload["body"] = '<link rel="manifest" id="MANIFEST_LINK" href="/data/manifest/" crossorigin="use-credentials" />';
|
||||||
|
|
||||||
// get link tags
|
// get link tags
|
||||||
preg_match_all(
|
preg_match_all(
|
||||||
'/< *link +(.*)[\/]?>/Uixs',
|
'/< *link +(.*)[\/]?>/Uixs',
|
||||||
$payload["body"],
|
$payload["body"],
|
||||||
$linktags
|
$linktags
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Get relevant tags
|
Get relevant tags
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$linktags = $linktags[1];
|
$linktags = $linktags[1];
|
||||||
$attributes = [];
|
$attributes = [];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
header("Content-Type: text/plain");
|
header("Content-Type: text/plain");
|
||||||
print_r($linktags);
|
print_r($linktags);
|
||||||
print_r($payload);
|
print_r($payload);
|
||||||
die();*/
|
die();*/
|
||||||
|
|
||||||
for($i=0; $i<count($linktags); $i++){
|
for($i=0; $i<count($linktags); $i++){
|
||||||
|
|
||||||
// get attributes
|
// get attributes
|
||||||
preg_match_all(
|
preg_match_all(
|
||||||
'/([A-Za-z0-9]+) *= *("[^"]*"|[^" ]+)/s',
|
'/([A-Za-z0-9]+) *= *("[^"]*"|[^" ]+)/s',
|
||||||
$linktags[$i],
|
$linktags[$i],
|
||||||
$tags
|
$tags
|
||||||
);
|
);
|
||||||
|
|
||||||
for($k=0; $k<count($tags[1]); $k++){
|
for($k=0; $k<count($tags[1]); $k++){
|
||||||
|
|
||||||
$attributes[$i][] = [
|
$attributes[$i][] = [
|
||||||
"name" => $tags[1][$k],
|
"name" => $tags[1][$k],
|
||||||
"value" => trim($tags[2][$k], "\" \n\r\t\v\x00")
|
"value" => trim($tags[2][$k], "\" \n\r\t\v\x00")
|
||||||
@@ -101,22 +107,22 @@ class favicon{
|
|||||||
unset($linktags);
|
unset($linktags);
|
||||||
|
|
||||||
$href = [];
|
$href = [];
|
||||||
|
|
||||||
// filter out the tags we want
|
// filter out the tags we want
|
||||||
foreach($attributes as &$group){
|
foreach($attributes as &$group){
|
||||||
|
|
||||||
$tmp_href = null;
|
$tmp_href = null;
|
||||||
$tmp_rel = null;
|
$tmp_rel = null;
|
||||||
$badtype = false;
|
$badtype = false;
|
||||||
|
|
||||||
foreach($group as &$attribute){
|
foreach($group as &$attribute){
|
||||||
|
|
||||||
switch($attribute["name"]){
|
switch($attribute["name"]){
|
||||||
|
|
||||||
case "rel":
|
case "rel":
|
||||||
|
|
||||||
$attribute["value"] = strtolower($attribute["value"]);
|
$attribute["value"] = strtolower($attribute["value"]);
|
||||||
|
|
||||||
if(
|
if(
|
||||||
(
|
(
|
||||||
$attribute["value"] == "icon" ||
|
$attribute["value"] == "icon" ||
|
||||||
@@ -126,49 +132,49 @@ class favicon{
|
|||||||
$attribute["value"] == "mask-icon"
|
$attribute["value"] == "mask-icon"
|
||||||
) === false
|
) === false
|
||||||
){
|
){
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmp_rel = $attribute["value"];
|
$tmp_rel = $attribute["value"];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "type":
|
case "type":
|
||||||
$attribute["value"] = explode("/", $attribute["value"], 2);
|
$attribute["value"] = explode("/", $attribute["value"], 2);
|
||||||
|
|
||||||
if(strtolower($attribute["value"][0]) != "image"){
|
if(strtolower($attribute["value"][0]) != "image"){
|
||||||
|
|
||||||
$badtype = true;
|
$badtype = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "href":
|
case "href":
|
||||||
|
|
||||||
// must not contain invalid characters
|
// must not contain invalid characters
|
||||||
// must be bigger than 1
|
// must be bigger than 1
|
||||||
if(
|
if(
|
||||||
filter_var($attribute["value"], FILTER_SANITIZE_URL) == $attribute["value"] &&
|
filter_var($attribute["value"], FILTER_SANITIZE_URL) == $attribute["value"] &&
|
||||||
strlen($attribute["value"]) > 0
|
strlen($attribute["value"]) > 0
|
||||||
){
|
){
|
||||||
|
|
||||||
$tmp_href = $attribute["value"];
|
$tmp_href = $attribute["value"];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(
|
||||||
$badtype === false &&
|
$badtype === false &&
|
||||||
$tmp_rel !== null &&
|
$tmp_rel !== null &&
|
||||||
$tmp_href !== null
|
$tmp_href !== null
|
||||||
){
|
){
|
||||||
|
|
||||||
$href[$tmp_rel] = $tmp_href;
|
$href[$tmp_rel] = $tmp_href;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Priority list
|
Priority list
|
||||||
*/
|
*/
|
||||||
@@ -176,37 +182,37 @@ class favicon{
|
|||||||
header("Content-Type: text/plain");
|
header("Content-Type: text/plain");
|
||||||
print_r($href);
|
print_r($href);
|
||||||
die();*/
|
die();*/
|
||||||
|
|
||||||
if(isset($href["icon"])){ $href = $href["icon"]; }
|
if(isset($href["icon"])){ $href = $href["icon"]; }
|
||||||
elseif(isset($href["apple-touch-icon"])){ $href = $href["apple-touch-icon"]; }
|
elseif(isset($href["apple-touch-icon"])){ $href = $href["apple-touch-icon"]; }
|
||||||
elseif(isset($href["manifest"])){
|
elseif(isset($href["manifest"])){
|
||||||
|
|
||||||
// attempt to parse manifest, but fallback to []
|
// attempt to parse manifest, but fallback to []
|
||||||
$href = $this->parsemanifest($href["manifest"], $url);
|
$href = $this->parsemanifest($href["manifest"], $url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_array($href)){
|
if(is_array($href)){
|
||||||
|
|
||||||
if(isset($href["mask-icon"])){ $href = $href["mask-icon"]; }
|
if(isset($href["mask-icon"])){ $href = $href["mask-icon"]; }
|
||||||
elseif(isset($href["shortcut icon"])){ $href = $href["shortcut icon"]; }
|
elseif(isset($href["shortcut icon"])){ $href = $href["shortcut icon"]; }
|
||||||
else{
|
else{
|
||||||
|
|
||||||
$href = "/favicon.ico";
|
$href = "/favicon.ico";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$href = $this->proxy->getabsoluteurl($href, $url);
|
$href = $this->proxy->getabsoluteurl($href, $url);
|
||||||
/*
|
/*
|
||||||
header("Content-type: text/plain");
|
header("Content-type: text/plain");
|
||||||
echo $href;
|
echo $href;
|
||||||
die();*/
|
die();*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Download the favicon
|
Download the favicon
|
||||||
*/
|
*/
|
||||||
//$href = "https://git.lolcat.ca/assets/img/logo.svg";
|
//$href = "https://git.lolcat.ca/assets/img/logo.svg";
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$payload =
|
$payload =
|
||||||
$this->proxy->get(
|
$this->proxy->get(
|
||||||
@@ -215,24 +221,24 @@ class favicon{
|
|||||||
true,
|
true,
|
||||||
$url
|
$url
|
||||||
);
|
);
|
||||||
|
|
||||||
}catch(Exception $error){
|
}catch(Exception $error){
|
||||||
|
|
||||||
header("X-Error: Could not fetch the favicon (" . $error->getMessage() . ")");
|
header("X-Error: Could not fetch the favicon (" . $error->getMessage() . ")");
|
||||||
$this->favicon404();
|
$this->favicon404();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parse the file format
|
Parse the file format
|
||||||
*/
|
*/
|
||||||
$image = null;
|
$image = null;
|
||||||
$format = $this->proxy->getimageformat($payload, $image);
|
$format = $this->proxy->getimageformat($payload, $image);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert the image
|
Convert the image
|
||||||
*/
|
*/
|
||||||
try{
|
try{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@todo: fix issues with avif+transparency
|
@todo: fix issues with avif+transparency
|
||||||
maybe using GD as fallback?
|
maybe using GD as fallback?
|
||||||
@@ -240,32 +246,32 @@ class favicon{
|
|||||||
if($format !== false){
|
if($format !== false){
|
||||||
$image->setFormat($format);
|
$image->setFormat($format);
|
||||||
}
|
}
|
||||||
|
|
||||||
$image->setBackgroundColor(new ImagickPixel("transparent"));
|
$image->setBackgroundColor(new ImagickPixel("transparent"));
|
||||||
$image->readImageBlob($payload["body"]);
|
$image->readImageBlob($payload["body"]);
|
||||||
$image->resizeImage(16, 16, imagick::FILTER_LANCZOS, 1);
|
$image->resizeImage(16, 16, imagick::FILTER_LANCZOS, 1);
|
||||||
$image->setFormat("png");
|
$image->setFormat("png");
|
||||||
|
|
||||||
$image = $image->getImageBlob();
|
$image = $image->getImageBlob();
|
||||||
|
|
||||||
// save favicon
|
// save favicon
|
||||||
$handle = fopen("icons/" . $this->filename . ".png", "w");
|
$handle = fopen($this->iconpath(), "w");
|
||||||
fwrite($handle, $image, strlen($image));
|
fwrite($handle, $image, strlen($image));
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
|
|
||||||
echo $image;
|
echo $image;
|
||||||
|
|
||||||
}catch(ImagickException $error){
|
}catch(ImagickException $error){
|
||||||
|
|
||||||
header("X-Error: Could not convert the favicon: (" . $error->getMessage() . ")");
|
header("X-Error: Could not convert the favicon: (" . $error->getMessage() . ")");
|
||||||
$this->favicon404();
|
$this->favicon404();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parsemanifest($href, $url){
|
private function parsemanifest($href, $url){
|
||||||
|
|
||||||
if(
|
if(
|
||||||
// check if base64-encoded JSON manifest
|
// check if base64-encoded JSON manifest
|
||||||
preg_match(
|
preg_match(
|
||||||
@@ -274,17 +280,17 @@ class favicon{
|
|||||||
$json
|
$json
|
||||||
)
|
)
|
||||||
){
|
){
|
||||||
|
|
||||||
$json = base64_decode($json[1]);
|
$json = base64_decode($json[1]);
|
||||||
|
|
||||||
if($json === false){
|
if($json === false){
|
||||||
|
|
||||||
// could not decode the manifest regex
|
// could not decode the manifest regex
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$json =
|
$json =
|
||||||
$this->proxy->get(
|
$this->proxy->get(
|
||||||
@@ -293,76 +299,81 @@ class favicon{
|
|||||||
false,
|
false,
|
||||||
$url
|
$url
|
||||||
);
|
);
|
||||||
|
|
||||||
$json = $json["body"];
|
$json = $json["body"];
|
||||||
|
|
||||||
}catch(Exception $error){
|
}catch(Exception $error){
|
||||||
|
|
||||||
// could not fetch the manifest
|
// could not fetch the manifest
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$json = json_decode($json, true);
|
$json = json_decode($json, true);
|
||||||
|
|
||||||
if($json === null){
|
if($json === null){
|
||||||
|
|
||||||
// manifest did not return valid json
|
// manifest did not return valid json
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(
|
if(
|
||||||
isset($json["start_url"]) &&
|
isset($json["start_url"]) &&
|
||||||
$this->proxy->validateurl($json["start_url"])
|
$this->proxy->validateurl($json["start_url"])
|
||||||
){
|
){
|
||||||
|
|
||||||
$url = $json["start_url"];
|
$url = $json["start_url"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isset($json["icons"][0]["src"])){
|
if(!isset($json["icons"][0]["src"])){
|
||||||
|
|
||||||
// manifest does not contain a path to the favicon
|
// manifest does not contain a path to the favicon
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// horay, return the favicon path
|
// horay, return the favicon path
|
||||||
return $json["icons"][0]["src"];
|
return $json["icons"][0]["src"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function iconpath() {
|
||||||
|
// $this->filename can be trusted
|
||||||
|
return config::ICON_DIR . "/" . $this->filename . ".png";
|
||||||
|
}
|
||||||
|
|
||||||
private function favicon404(){
|
private function favicon404(){
|
||||||
|
|
||||||
// fallback to google favicons
|
// fallback to google favicons
|
||||||
// ... probably blocked by cuckflare
|
// ... probably blocked by cuckflare
|
||||||
try{
|
try{
|
||||||
|
|
||||||
$image =
|
$image =
|
||||||
$this->proxy->get(
|
$this->proxy->get(
|
||||||
"https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://{$this->filename}&size=16",
|
"https://t0.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=http://{$this->filename}&size=16",
|
||||||
$this->proxy::req_image
|
$this->proxy::req_image
|
||||||
);
|
);
|
||||||
}catch(Exception $error){
|
}catch(Exception $error){
|
||||||
|
|
||||||
$this->defaulticon();
|
$this->defaulticon();
|
||||||
}
|
}
|
||||||
|
|
||||||
// write favicon from google
|
// write favicon from google
|
||||||
$handle = fopen("icons/" . $this->filename . ".png", "w");
|
$handle = fopen($this->iconpath(), "w");
|
||||||
fwrite($handle, $image["body"], strlen($image["body"]));
|
fwrite($handle, $image["body"], strlen($image["body"]));
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
|
|
||||||
echo $image["body"];
|
echo $image["body"];
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function defaulticon(){
|
private function defaulticon(){
|
||||||
|
|
||||||
// give 404 and fuck off
|
// give 404 and fuck off
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
|
|
||||||
$handle = fopen("lib/favicon404.png", "r");
|
$handle = fopen("lib/favicon404.png", "r");
|
||||||
echo fread($handle, filesize("lib/favicon404.png"));
|
echo fread($handle, filesize("lib/favicon404.png"));
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
|
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 753 B |
@@ -24,7 +24,7 @@ class anubis{
|
|||||||
"script"
|
"script"
|
||||||
);
|
);
|
||||||
|
|
||||||
if(count($script) === 0){
|
if($script === false){
|
||||||
|
|
||||||
throw new Exception("Failed to scrape anubis challenge data");
|
throw new Exception("Failed to scrape anubis challenge data");
|
||||||
}
|
}
|
||||||
|
@@ -1,27 +1,27 @@
|
|||||||
<?php
|
<?php
|
||||||
class backend{
|
class backend{
|
||||||
|
|
||||||
public function __construct($scraper){
|
public function __construct($scraper){
|
||||||
|
|
||||||
$this->scraper = $scraper;
|
$this->scraper = $scraper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Proxy stuff
|
Proxy stuff
|
||||||
*/
|
*/
|
||||||
public function get_ip(){
|
public function get_ip(){
|
||||||
|
|
||||||
$pool = constant("config::PROXY_" . strtoupper($this->scraper));
|
$pool = constant("config::PROXY_" . strtoupper($this->scraper));
|
||||||
if($pool === false){
|
if($pool === false){
|
||||||
|
|
||||||
// we don't want a proxy, fuck off!
|
// we don't want a proxy, fuck off!
|
||||||
return 'raw_ip::::';
|
return 'raw_ip::::';
|
||||||
}
|
}
|
||||||
|
|
||||||
// indent
|
// indent
|
||||||
$proxy_index_raw = apcu_inc("p." . $this->scraper);
|
$proxy_index_raw = apcu_inc("p." . $this->scraper);
|
||||||
|
|
||||||
$proxylist = file_get_contents("data/proxies/" . $pool . ".txt");
|
$proxylist = file_get_contents("data/" . $pool . ".txt");
|
||||||
$proxylist = explode("\n", $proxylist);
|
$proxylist = explode("\n", $proxylist);
|
||||||
|
|
||||||
// ignore empty or commented lines
|
// ignore empty or commented lines
|
||||||
@@ -29,15 +29,15 @@ class backend{
|
|||||||
$entry = ltrim($entry);
|
$entry = ltrim($entry);
|
||||||
return strlen($entry) > 0 && substr($entry, 0, 1) != "#";
|
return strlen($entry) > 0 && substr($entry, 0, 1) != "#";
|
||||||
});
|
});
|
||||||
|
|
||||||
$proxylist = array_values($proxylist);
|
$proxylist = array_values($proxylist);
|
||||||
|
|
||||||
return $proxylist[$proxy_index_raw % count($proxylist)];
|
return $proxylist[$proxy_index_raw % count($proxylist)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function is also called directly on nextpage
|
// this function is also called directly on nextpage
|
||||||
public function assign_proxy(&$curlproc, string $ip){
|
public function assign_proxy(&$curlproc, string $ip){
|
||||||
|
|
||||||
// parse proxy line
|
// parse proxy line
|
||||||
[
|
[
|
||||||
$type,
|
$type,
|
||||||
@@ -46,34 +46,34 @@ class backend{
|
|||||||
$username,
|
$username,
|
||||||
$password
|
$password
|
||||||
] = explode(":", $ip, 5);
|
] = explode(":", $ip, 5);
|
||||||
|
|
||||||
switch($type){
|
switch($type){
|
||||||
|
|
||||||
case "raw_ip":
|
case "raw_ip":
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "http":
|
case "http":
|
||||||
case "https":
|
case "https":
|
||||||
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
|
||||||
curl_setopt($curlproc, CURLOPT_PROXY, $type . "://" . $address . ":" . $port);
|
curl_setopt($curlproc, CURLOPT_PROXY, $type . "://" . $address . ":" . $port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "socks4":
|
case "socks4":
|
||||||
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
|
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
|
||||||
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "socks5":
|
case "socks5":
|
||||||
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
|
||||||
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "socks4a":
|
case "socks4a":
|
||||||
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
|
curl_setopt($curlproc, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
|
||||||
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "socks5_hostname":
|
case "socks5_hostname":
|
||||||
case "socks5h":
|
case "socks5h":
|
||||||
case "socks5a":
|
case "socks5a":
|
||||||
@@ -81,25 +81,25 @@ class backend{
|
|||||||
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
curl_setopt($curlproc, CURLOPT_PROXY, $address . ":" . $port);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($username != ""){
|
if($username != ""){
|
||||||
|
|
||||||
curl_setopt($curlproc, CURLOPT_PROXYUSERPWD, $username . ":" . $password);
|
curl_setopt($curlproc, CURLOPT_PROXYUSERPWD, $username . ":" . $password);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Next page stuff
|
Next page stuff
|
||||||
*/
|
*/
|
||||||
public function store(string $payload, string $page, string $proxy){
|
public function store(string $payload, string $page, string $proxy){
|
||||||
|
|
||||||
$key = sodium_crypto_secretbox_keygen();
|
$key = sodium_crypto_secretbox_keygen();
|
||||||
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
|
||||||
|
|
||||||
$requestid = apcu_inc("requestid");
|
$requestid = apcu_inc("requestid");
|
||||||
|
|
||||||
apcu_store(
|
apcu_store(
|
||||||
$page[0] . "." . // first letter of page name
|
$page[0] . "." . // first letter of page name
|
||||||
$this->scraper . // scraper name
|
$this->scraper . // scraper name
|
||||||
@@ -117,31 +117,31 @@ class backend{
|
|||||||
900 // cache information for 15 minutes
|
900 // cache information for 15 minutes
|
||||||
);
|
);
|
||||||
|
|
||||||
return
|
return
|
||||||
$this->scraper . $requestid . "." .
|
$this->scraper . $requestid . "." .
|
||||||
rtrim(strtr(base64_encode($key), '+/', '-_'), '=');
|
rtrim(strtr(base64_encode($key), '+/', '-_'), '=');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get(string $npt, string $page){
|
public function get(string $npt, string $page){
|
||||||
|
|
||||||
$page = $page[0];
|
$page = $page[0];
|
||||||
$explode = explode(".", $npt, 2);
|
$explode = explode(".", $npt, 2);
|
||||||
|
|
||||||
if(count($explode) !== 2){
|
if(count($explode) !== 2){
|
||||||
|
|
||||||
throw new Exception("Malformed nextPageToken!");
|
throw new Exception("Malformed nextPageToken!");
|
||||||
}
|
}
|
||||||
|
|
||||||
$apcu = $page . "." . $explode[0];
|
$apcu = $page . "." . $explode[0];
|
||||||
$key = $explode[1];
|
$key = $explode[1];
|
||||||
|
|
||||||
$payload = apcu_fetch($apcu);
|
$payload = apcu_fetch($apcu);
|
||||||
|
|
||||||
if($payload === false){
|
if($payload === false){
|
||||||
|
|
||||||
throw new Exception("The next page token is invalid or has expired!");
|
throw new Exception("The next page token is invalid or has expired!");
|
||||||
}
|
}
|
||||||
|
|
||||||
$key =
|
$key =
|
||||||
base64_decode(
|
base64_decode(
|
||||||
str_pad(
|
str_pad(
|
||||||
@@ -151,7 +151,7 @@ class backend{
|
|||||||
STR_PAD_RIGHT
|
STR_PAD_RIGHT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// decrypt and decompress data
|
// decrypt and decompress data
|
||||||
$payload[2] =
|
$payload[2] =
|
||||||
gzinflate(
|
gzinflate(
|
||||||
@@ -161,15 +161,15 @@ class backend{
|
|||||||
$key
|
$key
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if($payload[2] === false){
|
if($payload[2] === false){
|
||||||
|
|
||||||
throw new Exception("The next page token is invalid or has expired!");
|
throw new Exception("The next page token is invalid or has expired!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the key after using successfully
|
// remove the key after using successfully
|
||||||
apcu_delete($apcu);
|
apcu_delete($apcu);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
$payload[2], // data
|
$payload[2], // data
|
||||||
$payload[1] // proxy
|
$payload[1] // proxy
|
||||||
|
@@ -73,7 +73,6 @@ class frontend{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function loadheader(array $get, array $filters, string $page){
|
public function loadheader(array $get, array $filters, string $page){
|
||||||
|
|
||||||
echo
|
echo
|
||||||
$this->load("header.html", [
|
$this->load("header.html", [
|
||||||
"title" => trim(htmlspecialchars($get["s"]) . " ({$page})"),
|
"title" => trim(htmlspecialchars($get["s"]) . " ({$page})"),
|
||||||
@@ -83,60 +82,6 @@ class frontend{
|
|||||||
"tabs" => $this->generatehtmltabs($page, $get["s"]),
|
"tabs" => $this->generatehtmltabs($page, $get["s"]),
|
||||||
"filters" => $this->generatehtmlfilters($filters, $get)
|
"filters" => $this->generatehtmlfilters($filters, $get)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$headers_raw = getallheaders();
|
|
||||||
$header_keys = [];
|
|
||||||
$user_agent = "";
|
|
||||||
$bad_header = false;
|
|
||||||
|
|
||||||
// block bots that present X-Forwarded-For, Via, etc
|
|
||||||
foreach($headers_raw as $headerkey => $headervalue){
|
|
||||||
|
|
||||||
$headerkey = strtolower($headerkey);
|
|
||||||
if($headerkey == "user-agent"){
|
|
||||||
|
|
||||||
$user_agent = $headervalue;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check header key
|
|
||||||
if(in_array($headerkey, config::FILTERED_HEADER_KEYS)){
|
|
||||||
|
|
||||||
$bad_header = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SSL check
|
|
||||||
$bad_ssl = false;
|
|
||||||
if(
|
|
||||||
isset($_SERVER["https"]) &&
|
|
||||||
$_SERVER["https"] == "on" &&
|
|
||||||
isset($_SERVER["SSL_CIPHER"]) &&
|
|
||||||
in_array($_SERVER["SSL_CIPHER"], config::FILTERED_HEADER_KEYS)
|
|
||||||
){
|
|
||||||
|
|
||||||
$bad_ssl = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(
|
|
||||||
$bad_header === true ||
|
|
||||||
$bad_ssl === true ||
|
|
||||||
$user_agent == "" ||
|
|
||||||
// user agent check
|
|
||||||
preg_match(
|
|
||||||
config::HEADER_REGEX,
|
|
||||||
$user_agent
|
|
||||||
)
|
|
||||||
){
|
|
||||||
|
|
||||||
// bot detected !!
|
|
||||||
$this->drawerror(
|
|
||||||
"Tshh, blocked!",
|
|
||||||
'Your browser, IP or IP range has been blocked from this 4get instance.'
|
|
||||||
);
|
|
||||||
die();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function drawerror($title, $error, $timetaken = null){
|
public function drawerror($title, $error, $timetaken = null){
|
||||||
@@ -178,7 +123,6 @@ class frontend{
|
|||||||
'<li>Remove keywords that could cause errors</li>' .
|
'<li>Remove keywords that could cause errors</li>' .
|
||||||
'<li><a href="/instances?target=' . $target . "&" . $this->buildquery($get, false) . '">Try your search on another 4get instance</a></li>' .
|
'<li><a href="/instances?target=' . $target . "&" . $this->buildquery($get, false) . '">Try your search on another 4get instance</a></li>' .
|
||||||
'</ul><br>' .
|
'</ul><br>' .
|
||||||
'If the error persists, please <a href="/about">contact the administrator</a>.',
|
|
||||||
$timetaken
|
$timetaken
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -719,7 +719,7 @@ class ddg{
|
|||||||
->getTextContent(
|
->getTextContent(
|
||||||
$json["suggestion"]
|
$json["suggestion"]
|
||||||
),
|
),
|
||||||
"correction" => $json["recourseText"]
|
"correction" => html_entity_decode($json["recourseText"])
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -317,14 +317,19 @@ class marginalia{
|
|||||||
//
|
//
|
||||||
// Bypass anubis check
|
// Bypass anubis check
|
||||||
//
|
//
|
||||||
|
/*
|
||||||
if(($anubis_key = apcu_fetch("marginalia_cookie")) === false){
|
if(($anubis_key = apcu_fetch("marginalia_cookie")) === false){
|
||||||
|
|
||||||
try{
|
try{
|
||||||
$html =
|
$html =
|
||||||
$this->get(
|
$this->get(
|
||||||
$proxy,
|
$proxy,
|
||||||
"https://old-search.marginalia.nu/"
|
"https://old-search.marginalia.nu/search",
|
||||||
|
[
|
||||||
|
"query" => $search
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
}catch(Exception $error){
|
}catch(Exception $error){
|
||||||
|
|
||||||
throw new Exception("Failed to get anubis challenge");
|
throw new Exception("Failed to get anubis challenge");
|
||||||
@@ -361,7 +366,7 @@ class marginalia{
|
|||||||
}
|
}
|
||||||
|
|
||||||
apcu_store("marginalia_cookie", $anubis_key);
|
apcu_store("marginalia_cookie", $anubis_key);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if($get["npt"]){
|
if($get["npt"]){
|
||||||
|
|
||||||
@@ -377,7 +382,7 @@ class marginalia{
|
|||||||
$proxy,
|
$proxy,
|
||||||
"https://old-search.marginalia.nu/search?" . $params,
|
"https://old-search.marginalia.nu/search?" . $params,
|
||||||
[],
|
[],
|
||||||
$anubis_key
|
//$anubis_key
|
||||||
);
|
);
|
||||||
}catch(Exception $error){
|
}catch(Exception $error){
|
||||||
|
|
||||||
@@ -408,7 +413,7 @@ class marginalia{
|
|||||||
$proxy,
|
$proxy,
|
||||||
"https://old-search.marginalia.nu/search",
|
"https://old-search.marginalia.nu/search",
|
||||||
$params,
|
$params,
|
||||||
$anubis_key
|
//$anubis_key
|
||||||
);
|
);
|
||||||
}catch(Exception $error){
|
}catch(Exception $error){
|
||||||
|
|
||||||
|
@@ -4,20 +4,20 @@
|
|||||||
--282828: #282828;
|
--282828: #282828;
|
||||||
--3c3836: #3c3836;
|
--3c3836: #3c3836;
|
||||||
--504945: #504945;
|
--504945: #504945;
|
||||||
|
|
||||||
/* font */
|
/* font */
|
||||||
--928374: #928374;
|
--928374: #928374;
|
||||||
--a89984: #a89984;
|
--a89984: #a89984;
|
||||||
--bdae93: #bdae93;
|
--bdae93: #bdae93;
|
||||||
--8ec07c: #8ec07c;
|
--8ec07c: #8ec07c;
|
||||||
--ebdbb2: #ebdbb2;
|
--ebdbb2: #ebdbb2;
|
||||||
|
|
||||||
/* code highlighter */
|
/* code highlighter */
|
||||||
--comment: #9e8e73;
|
--comment: #9e8e73;
|
||||||
--default: #d4be98;
|
--default: #d4be98;
|
||||||
--keyword: #d8a657;
|
--keyword: #d8a657;
|
||||||
--string: #7daea7;
|
--string: #7daea7;
|
||||||
|
|
||||||
/* color codes for instance list */
|
/* color codes for instance list */
|
||||||
--green: #b8bb26;
|
--green: #b8bb26;
|
||||||
--yellow: #d8a657;
|
--yellow: #d8a657;
|
||||||
@@ -258,7 +258,7 @@ h3,h4,h5,h6{
|
|||||||
font-family:Times;
|
font-family:Times;
|
||||||
width:100%;
|
width:100%;
|
||||||
height:100%;
|
height:100%;
|
||||||
background:var(--282828);
|
background: none;
|
||||||
display:block;
|
display:block;
|
||||||
object-fit:contain;
|
object-fit:contain;
|
||||||
}
|
}
|
||||||
@@ -1300,20 +1300,20 @@ table tr a:last-child{
|
|||||||
Responsive design
|
Responsive design
|
||||||
*/
|
*/
|
||||||
@media only screen and (max-width: 1550px){
|
@media only screen and (max-width: 1550px){
|
||||||
|
|
||||||
.web .right-right,
|
.web .right-right,
|
||||||
.web .right-left{
|
.web .right-left{
|
||||||
float:none;
|
float:none;
|
||||||
width:initial;
|
width:initial;
|
||||||
padding:0 0 0 15px;
|
padding:0 0 0 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web .left,
|
.web .left,
|
||||||
.searchbox,
|
.searchbox,
|
||||||
#images .infobox{
|
#images .infobox{
|
||||||
width:60%;
|
width:60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web .right-wrapper{
|
.web .right-wrapper{
|
||||||
width:40%;
|
width:40%;
|
||||||
}
|
}
|
||||||
@@ -1323,43 +1323,43 @@ table tr a:last-child{
|
|||||||
form{
|
form{
|
||||||
padding-top:27px;
|
padding-top:27px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation{
|
.navigation{
|
||||||
left:0;
|
left:0;
|
||||||
right:unset;
|
right:unset;
|
||||||
line-height:22px;
|
line-height:22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nextpage.img{
|
.nextpage.img{
|
||||||
width:initial;
|
width:initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web .right-right,
|
.web .right-right,
|
||||||
.web .right-left{
|
.web .right-left{
|
||||||
border:none;
|
border:none;
|
||||||
padding:0;
|
padding:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web .right-wrapper{
|
.web .right-wrapper{
|
||||||
float:none;
|
float:none;
|
||||||
padding:0;
|
padding:0;
|
||||||
width:initial;
|
width:initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web .left,
|
.web .left,
|
||||||
.searchbox{
|
.searchbox{
|
||||||
width:100%;
|
width:100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
body:not(.instances) table td{
|
body:not(.instances) table td{
|
||||||
display:block;
|
display:block;
|
||||||
width:100%;
|
width:100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
table a{
|
table a{
|
||||||
padding:0;
|
padding:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web.has-answer .left::before{
|
.web.has-answer .left::before{
|
||||||
display:block;
|
display:block;
|
||||||
content:"Results";
|
content:"Results";
|
||||||
@@ -1368,16 +1368,16 @@ table tr a:last-child{
|
|||||||
margin-bottom:17px;
|
margin-bottom:17px;
|
||||||
color:var(--bdae93);
|
color:var(--bdae93);
|
||||||
}
|
}
|
||||||
|
|
||||||
.web .answer{
|
.web .answer{
|
||||||
max-height:200px;
|
max-height:200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.web .wiki-head tr td:first-child,
|
.web .wiki-head tr td:first-child,
|
||||||
.web .info-table tr td:first-child{
|
.web .info-table tr td:first-child{
|
||||||
text-decoration:underline;
|
text-decoration:underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#images .infobox{
|
#images .infobox{
|
||||||
width:100%;
|
width:100%;
|
||||||
}
|
}
|
||||||
|
@@ -84,7 +84,7 @@ if($results["spelling"]["type"] != "no_correction"){
|
|||||||
'&' .
|
'&' .
|
||||||
$frontend->buildquery($get, true) .
|
$frontend->buildquery($get, true) .
|
||||||
'&spellcheck=no">' .
|
'&spellcheck=no">' .
|
||||||
$results["spelling"]["correction"] .
|
htmlspecialchars($results["spelling"]["correction"]) .
|
||||||
'</a>?' .
|
'</a>?' .
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
|
2
ups.json
2
ups.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"upstream": "https://git.lolcat.ca/lolcat/4get",
|
"upstream": "https://git.lolcat.ca/lolcat/4get",
|
||||||
"provider": "gitea",
|
"provider": "gitea",
|
||||||
"commit": "a2bc1e6190bab561b7244e2e9bbda994ab0d0d31",
|
"commit": "430c0a2f0f72f1254ab65d53f13640fe02418f05",
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"s/--- a\\//--- a\\/src\\//g",
|
"s/--- a\\//--- a\\/src\\//g",
|
||||||
"s/+++ b\\//+++ b\\/src\\//g"
|
"s/+++ b\\//+++ b\\/src\\//g"
|
||||||
|
Reference in New Issue
Block a user