diff --git a/Dockerfile b/Dockerfile index 7677fe1..26ff84d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,29 +1,21 @@ -FROM php:7.4-apache as builder +FROM node:22.12-alpine AS builder -RUN apt-get update && apt-get install -y git ssl-cert \ - && git clone 'https://github.com/SimplyEdit/simplycode.git' /app/simplycode +RUN apk add --no-cache bash git \ + && mkdir /app \ + && git -C /app/ clone 'https://github.com/SimplyEdit/simplycode-electron.git' \ + && git -C /app/ clone 'https://github.com/SimplyEdit/simplyedit-backend.git' \ + && npm --prefix /app/simplycode-electron install FROM php:7.4-apache -COPY --from=builder /app/simplycode/lib /var/www/lib -COPY --from=builder /app/simplycode/www/api/.htaccess /var/www/html/api/.htaccess -COPY --from=builder /app/simplycode/www/api/data/generated.html /var/www/html/simplycode/index.html -COPY --from=builder /app/simplycode/www/api/index.php /var/www/html/api/index.php -COPY --from=builder /app/simplycode/www/css /var/www/html/simplycode/css -COPY --from=builder /app/simplycode/www/js /var/www/html/simplycode/js -COPY --from=builder /app/simplycode/www/simply /var/www/html/simplycode/simply +COPY lib/ /var/www/lib/ +COPY html/ /var/www/html/ -COPY --from=builder /etc/ssl/certs/ssl-cert-snakeoil.pem /etc/ssl/certs/ssl-cert-snakeoil.pem -COPY --from=builder /etc/ssl/private/ssl-cert-snakeoil.key /etc/ssl/private/ssl-cert-snakeoil.key +COPY --from=builder /app/simplycode-electron/simplycode/ /var/www/html/simplycode/ +COPY --from=builder /app/simplyedit-backend/www/ /var/www/www/ -COPY 000-default.conf /etc/apache2/sites-available/000-default.conf -COPY entrypoint.sh /entrypoint.sh -COPY 403.php /var/www/html/403.php +RUN echo "ServerName simplycode" >> /etc/apache2/apache2.conf \ + && a2enmod --quiet rewrite ssl headers \ + && chmod +x /var/www/lib/entrypoint.sh -RUN a2enmod --quiet rewrite ssl headers \ - && chmod +x /entrypoint.sh \ - && ln -s /var/www/html/simplycode/js/ /var/www/html/js \ - && ln -s /var/www/www/api/data/generated.html /var/www/html/index.html \ - && mkdir /var/www/html/data && echo '{}' > /var/www/html/data/data.json - -ENTRYPOINT ["/entrypoint.sh"] +ENTRYPOINT ["/var/www/lib/entrypoint.sh"] diff --git a/bin/run-simplycode-docker.sh b/bin/run-simplycode-docker.sh new file mode 100755 index 0000000..08881e8 --- /dev/null +++ b/bin/run-simplycode-docker.sh @@ -0,0 +1,231 @@ +#!/usr/bin/env bash + +set -o errexit # Exit script when a command exits with non-zero status. +set -o errtrace # Exit on error inside any functions or sub-shells. +set -o nounset # Exit script on use of an undefined variable. +set -o pipefail # Return exit status of the last command in the pipe that exited with a non-zero exit code + +: "${DOCKER:=docker}" + +# ============================================================================== +# Exit codes +# ------------------------------------------------------------------------------ +: readonly -i "${EXIT_OK:=0}" +: readonly -i "${EXIT_NOT_ENOUGH_PARAMETERS:=65}" +: readonly -i "${EXIT_INVALID_PARAMETER:=66}" +: readonly -i "${EXIT_COULD_NOT_FIND_DIRECTORY:=75}" +: readonly -i "${EXIT_NOT_CORRECT_TYPE:=81}" + +# ------------------------------------------------------------------------------ +# Foreground colors +# ------------------------------------------------------------------------------ +: readonly "${COLOR_BLUE:=$(tput setaf 4)}" +: readonly "${COLOR_GREEN:=$(tput setaf 2)}" +: readonly "${COLOR_RED:=$(tput setaf 1)}" +: readonly "${COLOR_WHITE:=$(tput setaf 7)}" +# ------------------------------------------------------------------------------ +: readonly "${RESET_TEXT:=$(tput sgr0)}" # turn off all attributes +# ============================================================================== + + +# ============================================================================== +## Run the SimplyCode Docker container +# ------------------------------------------------------------------------------ +## \nUsage: $0 [-dh][-i ] +## +## Where: +## is an alternative Docker image to use +## is the path to the SimplyCode project to run +## +## Options: +## -d|--dry-run Show the command that would be run without executing it +## -h|--help Print this help dialogue and exit +## -i|--docker-image= Use the specified Docker image +## +## Any additional arguments will be passed to the `docker run` command. +## +## For example: +## +## $0 /bin/bash +## +## The Docker executable can be overridden by setting the DOCKER environmental +## variable before calling this script: +## +## DOCKER=/usr/local/docker $0 +## +## The SimplyCode Docker container will be run with the given project path mounted +## to the container's /var/www/www/api/data directory. If the project has an assets +## directory, this will be mounted to /var/www/html/assets. +# ============================================================================== +usage() { + local sScript sUsage + + sScript="$(basename "$0")" + sUsage="$(grep '^##' < "$0" | cut -c4-)" + + echo -e "${sUsage//\$0/${sScript}}" +} + +error(){ + message "ERROR" "${COLOR_RED}" "${@}" >&2 +} + +info(){ + message "INFO" "${COLOR_BLUE}" "${@}" +} + +message(){ + local sType="${1?Three parameters required: }" + local sColor="${2?Three parameters required: }" + local sMessage="${3?Three parameters required: }" + + echo -e "${COLOR_WHITE}[${sColor}${sType}${COLOR_WHITE}]${RESET_TEXT} ${sMessage}" + + # Each additional parameter will be treated as extra information to display with the error + if [[ "$#" -gt 3 ]]; then + shift 3 + for sMessage in "$@"; do + echo -e " ${sMessage}" + done + fi +} + +run_simplycode_docker() { + dryRun() { + local sResult + + DOCKER='echo' + sResult=$(executeCommand "${@}") + + iLines=$(echo "${sResult}" | sed -E 's/ --/\n--/g' | wc -l) + sResult="$(echo -n "${sResult}" | sed -E 's/ --/ \\\n --/g' | sed -n "1,${iLines}p")" + + echo -en "docker " + echo -n "${sResult}" | head -n -1 + echo -n "${sResult}" | tail -n 1 | cut -d ' ' -f 5-6 | sed -E 's/$/ \\/g' | sed 's/^/ /' + echo -n "${sResult}" | tail -n 1 | cut -d ' ' -f 7- | sed -E 's/ / \\\n/g' | sed 's/^/ /' + } + + executeCommand() { + local sDockerImage sProjectPath + + readonly sDockerImage="${1?Two parameters required: }" + shift + readonly sProjectPath="${1?Two parameters required: }" + shift + + # ====================================================================== + # Build the run command + # ---------------------------------------------------------------------- + local -a aCommand=("${DOCKER}" 'run') + + aCommand+=( + '--env' "USER_GID=$(id -g)" + '--env' "USER_ID=$(id -u)" + '--interactive' + '--network=default' + '--publish' '80:80' + '--publish' '443:443' + '--rm' + '--tty' + '--volume' "${sProjectPath}:/var/www/www/api/data" + ) + + if [[ -d "${sProjectPath}/assets" ]]; then + aCommand+=( + '--volume' "${sProjectPath}/assets:/var/www/html/assets" + ) + fi + + aCommand+=( + "${sDockerImage}" + "${@}" + ) + + # @TODO: Split command creation and execution into separate functions + # so dry-run can be simplified + + "${aCommand[@]}" + } + + local -a aParameters + local sArgument sDockerImage + local bDryRun=false + + aParameters=() + + sDockerImage='ghcr.io/simplyedit/simplycode-docker:main' + + while (( "$#" )); do + sArgument="${1}" + shift + case "${sArgument}" in + -d | --dry-run) + bDryRun=true + ;; + + -\? | -h | --help) + usage + exit "${EXIT_OK}" + ;; + + -i | --docker-image | --docker-image=?*) + # If the parameter contains a `=` the path is part of the param, so we need to split it to get the value + if grep '=' <(echo "${sArgument}");then + sDockerImage="${sArgument#*=}" + else + # Else, the next param is the value, unless no param is provided + if [[ -n "${1:-}" && ! "${1}" =~ ^- ]]; then + sDockerImage="${1}" + shift + else + error "No value provided for ${sDockerImage}" "Call with --help for more information." + exit "${EXIT_NOT_ENOUGH_PARAMETERS}" + fi + fi + ;; + + --*|-*) + error "Invalid option '${sArgument}'" "Call with --help for more information." + exit "${EXIT_INVALID_PARAMETER}" + ;; + + *) + aParameters+=("${sArgument}") + ;; + esac + done + + if [[ "${#aParameters[@]}" -lt 1 ]]; then + error "One parameter required: " "Call with --help for more information." + exit "${EXIT_NOT_ENOUGH_PARAMETERS}" + fi + + local sProjectPath="${aParameters[0]}" + sProjectPath="$(realpath "${sProjectPath}")" + aParameters=( "${aParameters[@]:1}" ) + + if [[ ! -e "${sProjectPath}" ]];then + error "Could not find directory: ${sProjectPath}" + exit "${EXIT_COULD_NOT_FIND_DIRECTORY}" + elif [[ ! -d "${sProjectPath}" ]];then + error "Provided path is not a directory: ${sProjectPath}" + exit "${EXIT_NOT_CORRECT_TYPE}" + fi + + if [[ "${bDryRun}" == true ]]; then + info "Dry run enabled. The following command would be run:\n" + dryRun "${sDockerImage}" "${sProjectPath}" "${aParameters[@]}" + echo "" + else + executeCommand "${sDockerImage}" "${sProjectPath}" "${aParameters[@]}" + fi +} + +if [[ ${BASH_SOURCE[0]} != "$0" ]]; then + export -f run_simplycode_docker +else + run_simplycode_docker "${@}" +fi + +#EOF diff --git a/html/.htaccess b/html/.htaccess new file mode 100644 index 0000000..6296c0b --- /dev/null +++ b/html/.htaccess @@ -0,0 +1,39 @@ + + + Order Allow,Deny + Deny from all + + + + Header set Cache-Control "max-age=0, public, must-revalidate" + +RewriteEngine on +# +# RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] +# +# RewriteCond %{REQUEST_METHOD} PUT +# RewriteRule ^(.*)$ simply-edit/store.php [L] +# +# RewriteCond %{REQUEST_METHOD} DELETE +# RewriteRule ^(.*)$ simply-edit/store.php [L] +# +# RewriteCond %{QUERY_STRING} _method=(PUT|DELETE) +# RewriteRule ^(.*)$ simply-edit/store.php [L] +# + + RewriteRule ^logout$ simply-edit/logout.php [L] + #RewriteRule ^login$ simply-edit/login.php [L] + + + RewriteCond %{HTTP_USER_AGENT} Lynx|w3m|googlebot|baiduspider|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora\ link\ preview|showyoubot|outbrain|pinterest|slackbot|vkShare|Validator [NC,OR] + RewriteCond %{QUERY_STRING} _escaped_fragment_ + + # Only proxy the request to Prerender if it's a request for HTML + RewriteRule ^(?!.*?(\.js|\.css|\.xml|\.less|\.png|\.jpg|\.jpeg|\.gif|\.pdf|\.doc|\.txt|\.ico|\.rss|\.zip|\.mp3|\.rar|\.exe|\.wmv|\.doc|\.avi|\.ppt|\.mpg|\.mpeg|\.tif|\.wav|\.mov|\.psd|\.ai|\.xls|\.mp4|\.m4a|\.swf|\.dat|\.dmg|\.iso|\.flv|\.m4v|\.torrent|\.ttf|\.woff))(.*) simply-edit/prerender.php [L] + + +Options +Indexes + +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule .* simply-edit/router.php [L] \ No newline at end of file diff --git a/html/api/.htaccess b/html/api/.htaccess new file mode 100644 index 0000000..f509db6 --- /dev/null +++ b/html/api/.htaccess @@ -0,0 +1,9 @@ +RewriteEngine on + + RewriteCond %{QUERY_STRING} _method=(GET|PUT|DELETE) + RewriteRule ^(.*)$ index.php [L] + + +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule .* index.php [L] \ No newline at end of file diff --git a/html/api/index.php b/html/api/index.php new file mode 100755 index 0000000..29db492 --- /dev/null +++ b/html/api/index.php @@ -0,0 +1,132 @@ + $e->getCode(), "message" => $e->getMessage()], 501); + } + + function filenotfound($path) { + output(["error" => 404, "message" => "File not found"], 404); + } diff --git a/html/data/data.json b/html/data/data.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/html/data/data.json @@ -0,0 +1 @@ +{} diff --git a/000-default.conf b/lib/000-default.conf similarity index 100% rename from 000-default.conf rename to lib/000-default.conf diff --git a/403.php b/lib/403.php similarity index 100% rename from 403.php rename to lib/403.php diff --git a/lib/config.php b/lib/config.php new file mode 100644 index 0000000..db86a60 --- /dev/null +++ b/lib/config.php @@ -0,0 +1,27 @@ + /dev/null)" ]; then exec "${@}" else + runSetup runChecks if [ -d /var/www/html/assets ]; then @@ -105,6 +106,7 @@ guessUrl(){ echo "${url}" } + runChecks() { local pass=true local url @@ -119,9 +121,9 @@ runChecks() { "$(tput setaf 7)$(tput setab 2)" \ "$(tput sgr 0)" - echo "Contents of volume /var/www/www/api/data:" - find /var/www/www/api/data -maxdepth 1 -type d -exec echo -e "\t{}/" \; - find /var/www/www/api/data -maxdepth 1 -type f -exec echo -e "\t{}" \; + printf "Contents of volume /var/www/www/api/data:\n%s\n%s\n\n" \ + "$(find /var/www/www/api/data -maxdepth 1 -type d -exec echo -e "\t{}/" \; | sort)" \ + "$(find /var/www/www/api/data -maxdepth 1 -type f -exec echo -e "\t{}" \; | sort)" url="$(guessUrl)" readonly url @@ -130,4 +132,32 @@ runChecks() { fi } +runSetup() { + if [ ! -f /var/www/html/index.html ]; then + printf '%sFirst initialisation. Running setup...%s\n' \ + "$(tput setaf 7)$(tput setab 6)" \ + "$(tput sgr 0)" + + ( + PS4="$(echo -e " ")" + set -x + ln -s /var/www/html/simplycode/js/ /var/www/html/js + ln -s /var/www/www/api/data/generated.html /var/www/html/index.html + ln -s /var/www/www/api/data/generated.html /var/www/html/index.js + + mkdir -p /var/www/html/simply/ \ + && ln -s /var/www/html/simplycode/simply/databind.js /var/www/html/simply/databind.js + + mv /var/www/lib/000-default.conf /etc/apache2/sites-available/000-default.conf + mv /var/www/lib/403.php /var/www/html/403.php + mv /var/www/lib/server.key /etc/ssl/private/ssl-cert-snakeoil.key + mv /var/www/lib/server.pem /etc/ssl/certs/ssl-cert-snakeoil.pem + ) + + printf '%sSetup complete%s\n\n' \ + "$(tput setaf 7)$(tput setab 6)" \ + "$(tput sgr 0)" + fi +} + entrypoint "$@" diff --git a/lib/filesystem.php b/lib/filesystem.php new file mode 100755 index 0000000..4cb0284 --- /dev/null +++ b/lib/filesystem.php @@ -0,0 +1,445 @@ + $mimetypes ) { + if ( strpos($dirname, $path)===0 ) { + $allowed = true; + break; + } + } + if ( !$allowed ) { + throw new fsException('Access denied for '.$dirname.$filename, 106); + } + $finfo = new finfo(FILEINFO_MIME); + $mimetype = $finfo->file($tempfile); + $mimetypes[]= 'inode/x-empty'; + $mimetypeRe = '{'.implode('|', $mimetypes).'}i'; + if ( !preg_match($mimetypeRe, $mimetype) ) { + throw new fsException('Files with mimetype '.$mimetype.' are not allowed in '.$dirname, 108); + } + return true; + } + + private static function runChecks($method, $filename, $tempfile) + { + if ( !isset(self::$checks[$method]) ) { + return; + } + foreach ( self::$checks[$method] as $path => $checks ) { + foreach ( $checks as $callback ) { + if ( strpos($filename, $path)===0 ) { + $callback($filename, $tempfile); + } + } + } + } + + private static function dirNotWritable($dirname) + { + // FIXME: try to find out why it is not writable + // check if dir exists + // check if dir is writable + // check if dirname is a directory + // check permissions on dirname + // check owner and current user + + $error = error_get_last(); + var_dump($error); + throw new fsException("Directory $dirname is not writable: $error", 102); + } + + private static function fileNotWritable($file) + { + // FIXME: try to find out why it is not writable + $error = error_get_last(); + throw new fsException("File $file is not writeable: $error", 103); + } + + private static function renameFailed($file, $tempfile) + { + // FIXME: try to find out why the rename failed + unlink($tempfile); + throw new fsException('Could not move file contents to '.$file, 104); + } + + public static function exists($filename) { + $realfile = realpath(self::$basedir . $filename ); + return file_exists($realfile); + } + + public static function is_dir($filename) { + $realfile = realpath(self::$basedir . $filename ); + return is_dir($realfile); + } + + public static function scandir($filename) { + $realfile = realpath(self::$basedir . $filename ); + return scandir($realfile); + } + + private static function passthru($dirname, $filename, $hash=null) + { + clearstatcache(true); + list($realdir,$realfile)=self::realpaths($dirname,$filename); + $lock = self::lock($realfile); + + if ( !$lock ) { + throw new fsException('Could not lock '.$dirname.'/'.$filename.' for writing', 109); + } + /* PUT data comes in on the stdin stream */ + $in = fopen("php://input", "r"); + + /* Open a file for writing */ + $tempfile = tempnam($realdir, 'put-'); + chmod($tempfile, 0644); + $out = fopen($tempfile, "w"); + $res = stream_copy_to_stream($in,$out); + + /* Close the streams */ + fclose($out); + fclose($in); + + $exception = false; + try { + if ($res!==false) { + if ( !self::isAllowed($dirname, $filename, $tempfile) ) { + throw new fsException('Access denied for '.self::append($dirname,$filename), 106); + } + self::runChecks('put', self::append($dirname,$filename), $tempfile); + $res = rename($tempfile, $realfile); + if ($res == false) { + self::renameFailed(self::append($dirname,$filename), $tempfile); + } + } else { + } + } catch( \Exception $e ) { + $exception = $e; + } finally { + self::unlock($lock); + @unlink($tempfile); + } + if ( $exception ) { + throw $exception; + } + return true; + } + + private static function lock($filename) + { + clearstatcache(true); + $fp = fopen($filename.'.lock', 'w'); + if ( $fp && flock($fp, LOCK_EX ) ) { + return [ + 'resource' => $fp, + 'filename' => $filename + ]; + } + return false; + } + + private static function unlock($lock) + { + flock($lock['resource'], LOCK_UN); + fclose($lock['resource']); + unlink($lock['filename'].'.lock'); + } + + public static function cached($cacheName, $cacheTime) { + $cacheFile = self::$basedir . "/cache/" . $cacheName; + // Serve from the cache if it is younger than $cachetime + if (file_exists($cacheFile) && time() - $cacheTime < filemtime($cacheFile)) { + // echo "\n"; + readfile($cacheFile); + return true; + } else { + ob_start(); // Start the output buffer + return false; + } + } + + public static function saveCache($cacheName) { + $cacheDir = self::$basedir . "/cache/"; + if (file_exists($cacheDir)) { + // Cache the contents to a cache file + $cacheFile = self::$basedir . "/cache/" . $cacheName; + $tempFile = tempnam(self::$basedir . "/cache/", $cacheName); + + $cached = fopen($tempFile, 'w'); + fwrite($cached, ob_get_contents()); + fclose($cached); + if (file_exists($tempFile)) { + rename($tempFile, $cacheFile); + } + } + ob_end_flush(); // Send the output to the browser + } + + public static function glob($pattern) + { + return glob(rtrim(self::$basedir, '/') . '/' . $pattern); + } +} diff --git a/lib/http.php b/lib/http.php new file mode 100755 index 0000000..8c13cb8 --- /dev/null +++ b/lib/http.php @@ -0,0 +1,142 @@ + false ]; + } + foreach ( $list as $header => $extraInfo ) { + for ($i=$redirectLevel; $i>=0; $i--) { + $check = str_repeat($redirect, $i).$header; + if ( isset($_SERVER[$check]) ) { + return [$header, $_SERVER[$check]]; + } + } + } + return [false, '']; + } + + private static function parseAuthUser($auth) { + return explode(':',base64_decode(substr($auth, 6))); + } + + public static function getUser() + { + $checks = [ + 'PHP_AUTH_USER' => false, + 'REMOTE_USER' => false, + 'HTTP_AUTHORIZATION' => ['self','parseAuthUser'], + ]; + list($header, $headerValue) = self::getHeader($checks, 3); + if (isset($checks[$header]) && is_array($checks[$header])) { + $headerValue = call_user_func($checks[$header], $headerValue)[0]; + } + return $headerValue; + } + + public static function getPassword() + { + $checks = [ + 'PHP_AUTH_PW' => false, + 'HTTP_AUTHORIZATION' => ['self','parseAuthUser'], + ]; + list($header, $headerValue) = self::getHeader($checks, 3); + if (isset($checks[$header]) && is_array($checks[$header])) { + $headerValue = call_user_func($checks[$header], $headerValue)[1]; + } + return $headerValue; + } + + public static function getMethod() + { + list($header, $headerValue) = self::getHeader('REQUEST_METHOD',3); + if ($headerValue==='POST') { + if ($_GET['_method']=='PUT'||$_GET['_method']=='DELETE') { + $headerValue = $_GET['_method']; + } + } + return $headerValue; + } + + public static function request() + { + $target = preg_replace('@\?.*$@','',$_SERVER["REQUEST_URI"]); + $target = self::sanitizeTarget($target); + + preg_match('@(?.+/)?(?[^/]*)@',$target,$matches); + + $filename = isset($matches['filename']) ? $matches['filename'] : ''; + $dirname = ( isset($matches['dirname']) ? filesystem::path($matches['dirname']) : '/'); + $docroot = $_SERVER['DOCUMENT_ROOT']; + $subdir = filesystem::path( substr( dirname(dirname($_SERVER['SCRIPT_FILENAME'])), strlen($docroot) ) ); + $dirname = filesystem::path( substr($dirname, strlen($subdir) ) ); + $request = [ + 'protocol' => $_SERVER['SERVER_PROTOCOL']?:'HTTP/1.1', + 'method' => self::getMethod(), + 'target' => '/'.$target, + 'directory' => $dirname, + 'filename' => $filename, + 'user' => self::getUser(), + 'password' => self::getPassword(), + 'docroot' => $docroot + ]; + return $request; + } + + public static function response($status, $data='') + { + http_response_code($status); + header('Access-Control-Allow-Origin: *'); + switch(self::$format) { + case 'html': + echo $data; + break; + case 'svg': + header('Content-type: image/svg+xml'); + echo $data; + break; + case 'text': + header('Content-Type: text/plain'); + echo $data; + break; + case 'rawjson': + header('Content-Type: application/json'); + echo $data; + break; + case 'json': + default: + header('Content-Type: application/json'); + echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR); + break; + } + } + +} diff --git a/lib/router.php b/lib/router.php new file mode 100644 index 0000000..84590c8 --- /dev/null +++ b/lib/router.php @@ -0,0 +1,81 @@ +'; + } else if ( !filesystem::exists($templateDir) ) { + echo ''; + } else { + echo ''; + } + } + + http::response($status); + $contents = filesystem::get($templateDir, $template); + $contents = preg_replace('/ + + + + 404 Not Found + + +

Page not found (error: 404)

+ + + +HTML; + if ($request['target'] === '/favicon.ico') { + http::format('svg'); + http::response(200); + $contents = ''; + } + echo $contents; + } diff --git a/lib/server.cert b/lib/server.cert new file mode 100644 index 0000000..13d2208 --- /dev/null +++ b/lib/server.cert @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9TCCAt2gAwIBAgIUBMwKcK7jyq7/JsvPIKFRGAVJC3UwDQYJKoZIhvcNAQEL +BQAwgYkxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjERMA8GA1UEBwwIRW5zY2hl +ZGUxEjAQBgNVBAoMCU11emUgQi5WLjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxEzAR +BgNVBAMMClNpbXBseUNvZGUxGzAZBgkqhkiG9w0BCQEWDGluZm9AbXV6ZS5ubDAe +Fw0yMjA5MDExNDQzNTZaFw0yMjEwMDExNDQzNTZaMIGJMQswCQYDVQQGEwJOTDEL +MAkGA1UECAwCT1YxETAPBgNVBAcMCEVuc2NoZWRlMRIwEAYDVQQKDAlNdXplIEIu +Vi4xFDASBgNVBAsMC0RldmVsb3BtZW50MRMwEQYDVQQDDApTaW1wbHlDb2RlMRsw +GQYJKoZIhvcNAQkBFgxpbmZvQG11emUubmwwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDasxpoMCGUxBJFoIQAjg1FCBhh7yPqNffP+7MuKK6HGakrByzF +omv5Aah062d+mZ5zoqU9HWBEg06y4Y94eAyPi4XqEa7ghCeytOE15HZHoCg+1Sqq +OmRk0anWYtvTdV0ziOy3mPHs5F0eGbbvURKTfse6Y4k9knOj6GE2Pdf1MwaH4lN7 +fQyNke9kdUnZwYK2fMOnsL+1b4+7XmRI5Bu8jNX00EMV7D05uauIcEW24TXy+IMR +Ie1qN9P4hGJHcfhSwcPNL/PJilzNLtopcP9QYOQwhM9QaLXSJSeZ5+6PTOxoIHHH +gMq0KbXYT6TeaGSJPp5Fwe+funRfAGh0EpyzAgMBAAGjUzBRMB0GA1UdDgQWBBRl +TYkUSAIJl8UZ1xYppm+Tbs29kDAfBgNVHSMEGDAWgBRlTYkUSAIJl8UZ1xYppm+T +bs29kDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAcUStFyZyy +9tHOcMU6nPDcYN+6uHzagrhfIY9dkJOL5gEJfLRnIOzWAGy9lV9hMKpaR1SfwPwB +UnfQZdIBqJwZTdN8KZ2jb2I6+i7FjjFDcpJY5ubiMHAij1t9ZS2H/F2KCWs+5vpW +BTEjEwN3CKKjuby2DiaHc8jUOk1SemD9M9VidyOc7dDstn7KEh2jYpqYJOUcFZ27 +PrqUY7XQUtvHK3Iv6MFfXU/CgdSiExoIiuo8HIlq84YFZ7bkOd7VSS6DGEXgl0z8 +uuyJ8Qg21Y04ukJXtuaytTWvZPxSpo9MRT5eXZltNyDA0OagTXm+N+rVH1S6oxi4 +vW3e+eWuX+zV +-----END CERTIFICATE----- diff --git a/lib/server.key b/lib/server.key new file mode 100644 index 0000000..8fcdb1f --- /dev/null +++ b/lib/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDasxpoMCGUxBJF +oIQAjg1FCBhh7yPqNffP+7MuKK6HGakrByzFomv5Aah062d+mZ5zoqU9HWBEg06y +4Y94eAyPi4XqEa7ghCeytOE15HZHoCg+1SqqOmRk0anWYtvTdV0ziOy3mPHs5F0e +GbbvURKTfse6Y4k9knOj6GE2Pdf1MwaH4lN7fQyNke9kdUnZwYK2fMOnsL+1b4+7 +XmRI5Bu8jNX00EMV7D05uauIcEW24TXy+IMRIe1qN9P4hGJHcfhSwcPNL/PJilzN +LtopcP9QYOQwhM9QaLXSJSeZ5+6PTOxoIHHHgMq0KbXYT6TeaGSJPp5Fwe+funRf +AGh0EpyzAgMBAAECggEBALJmyhLVuH8XluQvdZ7SQibe3Kz/HCgRkC6cX2U3EG/q +0eHkv3QU88kzvgxqf4l5nRUtR2fcT8xz5L3tXFDkdTKfmUUA2cwSYiPYg6Kn1IjH +MC1ZTK2CZqULl2ToTfRoV/gTKS7319nry74jMeR1GRcyo5D7Y1fT4PuDM9HAjytX +y1KSJnuK+e87uAqfbiVLrJqZwUXBFJGMGcLr1BoOv8IVP4zymeQ0HZimy5SZmNlc +4AHENb5Jsxh1S6o61y5JHwEcuZd71Srv5NcWA4c/Z/zJe/1Kx7GXEZxX2kFwPHJM +K3KiHqndB7bz2tDWgAP6TJg+iodBf7bPIdodK1dYRvkCgYEA8LQ8jz0XLAxcuvNc +RGUGLm6+ai4j4b4EVZbHlbe0X64zzIYOi4ORRAoi/qGc5l4LtxawhARr21xRfrHZ +n/hG69MDUwIOOJnx4wwXy6tYCv5NJ6fRrhSHD1L+Ew51+kvM8caiGKEEn2rLp8iq +dOeucFRK8AEwsJ2fMfzowj32PjcCgYEA6JjmRJZsZsY4zfS0IfpSv3/DT6CL4kSz +4JjgOrxnWrXupZmrvQvCVb1nbjo2YMsYNmR4ktTDvW41sCtnSVwZvd2E5e3/9s8h +Vn3XLesh/ndzCfwfrSwfni1RsgOtnDz8C+T7AIT1pY/dxqHI/fC/sBeS1DByICUG +daN0sDjD92UCgYBroo06GD1WayjESLLHus0q0ka/wGY3OftCMqyJHJ7B8mojWQcE +CA9bd5TyfF5m/UML2k+QmVGJxByFJQ6F5EYCileANPkbAmwR9YRmhPZX5COoSfkP +eQp0Jc6LwvmqtV6t9v7hOI+SofTz0F247Skp/eeMr1uQfsuDVO7YfVCxvQKBgQDM +vYoz5ZUWAnYOFNBa+FXOa1Aoz1FSotcTZH48NYtktbCT5Gjfx3IQtuBMjsE/AocV +merolJCYNmLb59jLIl8mWc+Z9Z3SSxE1aR/4M3mA3PROXbgkXyqVuZ6n68TuOmBC +uBSZqG/yhGjbZ53cqgaRoq6ESQCseurssi0M0WruYQKBgQC8Rj325ZJxv8CPqQRa +bJEe30DpuC1f2eKRvdZq8ZAPY0FjS3ng1UMl1706B1t+1e3LYNTNnBQDh8BWXfX2 +M0VfpIp40VlfjCGq3VFA/R1hgqQM+n0ireTgROYXhhB31u2GMc0DgYznPq+wNQf/ +G84JiXOEqJLeG4BaAOv2mMgY3A== +-----END PRIVATE KEY----- diff --git a/lib/server.pem b/lib/server.pem new file mode 100644 index 0000000..13d2208 --- /dev/null +++ b/lib/server.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9TCCAt2gAwIBAgIUBMwKcK7jyq7/JsvPIKFRGAVJC3UwDQYJKoZIhvcNAQEL +BQAwgYkxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjERMA8GA1UEBwwIRW5zY2hl +ZGUxEjAQBgNVBAoMCU11emUgQi5WLjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxEzAR +BgNVBAMMClNpbXBseUNvZGUxGzAZBgkqhkiG9w0BCQEWDGluZm9AbXV6ZS5ubDAe +Fw0yMjA5MDExNDQzNTZaFw0yMjEwMDExNDQzNTZaMIGJMQswCQYDVQQGEwJOTDEL +MAkGA1UECAwCT1YxETAPBgNVBAcMCEVuc2NoZWRlMRIwEAYDVQQKDAlNdXplIEIu +Vi4xFDASBgNVBAsMC0RldmVsb3BtZW50MRMwEQYDVQQDDApTaW1wbHlDb2RlMRsw +GQYJKoZIhvcNAQkBFgxpbmZvQG11emUubmwwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDasxpoMCGUxBJFoIQAjg1FCBhh7yPqNffP+7MuKK6HGakrByzF +omv5Aah062d+mZ5zoqU9HWBEg06y4Y94eAyPi4XqEa7ghCeytOE15HZHoCg+1Sqq +OmRk0anWYtvTdV0ziOy3mPHs5F0eGbbvURKTfse6Y4k9knOj6GE2Pdf1MwaH4lN7 +fQyNke9kdUnZwYK2fMOnsL+1b4+7XmRI5Bu8jNX00EMV7D05uauIcEW24TXy+IMR +Ie1qN9P4hGJHcfhSwcPNL/PJilzNLtopcP9QYOQwhM9QaLXSJSeZ5+6PTOxoIHHH +gMq0KbXYT6TeaGSJPp5Fwe+funRfAGh0EpyzAgMBAAGjUzBRMB0GA1UdDgQWBBRl +TYkUSAIJl8UZ1xYppm+Tbs29kDAfBgNVHSMEGDAWgBRlTYkUSAIJl8UZ1xYppm+T +bs29kDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAcUStFyZyy +9tHOcMU6nPDcYN+6uHzagrhfIY9dkJOL5gEJfLRnIOzWAGy9lV9hMKpaR1SfwPwB +UnfQZdIBqJwZTdN8KZ2jb2I6+i7FjjFDcpJY5ubiMHAij1t9ZS2H/F2KCWs+5vpW +BTEjEwN3CKKjuby2DiaHc8jUOk1SemD9M9VidyOc7dDstn7KEh2jYpqYJOUcFZ27 +PrqUY7XQUtvHK3Iv6MFfXU/CgdSiExoIiuo8HIlq84YFZ7bkOd7VSS6DGEXgl0z8 +uuyJ8Qg21Y04ukJXtuaytTWvZPxSpo9MRT5eXZltNyDA0OagTXm+N+rVH1S6oxi4 +vW3e+eWuX+zV +-----END CERTIFICATE-----