removed older PHP references

This commit is contained in:
Paul Wilde 2021-08-16 20:20:30 +01:00
parent 14f30beb10
commit 0064740c13
20 changed files with 9 additions and 702 deletions

View file

@ -13,13 +13,13 @@ https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat, should
be able to auto-configure using this service. be able to auto-configure using this service.
## Installation ## Installation
The container file includes set up for an apache webserver to run the application. MailAutoConf runs its own webserver on port 8010.
You will need to supply a volume for the configuration file and port forwarding. You will need to supply a volume for the configuration file and port forwarding.
``` ```
podman run -dt \ podman run -dt \
--name mailautoconf \ --name mailautoconf \
-v ./config:/var/www/html/config \ -v ./config:/mailautoconf/config \
-p 8010:80 \ -p 8010:8010 \
pswilde/mailautoconf pswilde/mailautoconf
``` ```
You will need a reverse proxy server to publish to the outside world and handle SSL encryption. You will need a reverse proxy server to publish to the outside world and handle SSL encryption.
@ -40,7 +40,7 @@ server {
} }
} }
``` ```
First run will create sample.ini files in the config directory. Copy these to config.ini and services.ini and configure them to your needs. First run will create sample.yaml files in the config directory. Copy these to config.yaml and services.yaml and configure them to your needs.
MailAutoConf will handle all the URLs it's able to deal with, i.e. /mail/config-v1.1.xml, /Autodiscover/Autodiscover.xml automatically. MailAutoConf will handle all the URLs it's able to deal with, i.e. /mail/config-v1.1.xml, /Autodiscover/Autodiscover.xml automatically.

View file

@ -3,7 +3,7 @@ services:
mailautoconf: mailautoconf:
container_name: mailautoconf container_name: mailautoconf
ports: ports:
- '8010:80' - '8010:8010'
volumes: volumes:
- './config:/var/www/html/config' - './config:/mailautoconf/config'
image: pswilde/mailautoconf image: pswilde/mailautoconf

View file

@ -1,6 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
podman run --name mailautoconf \ podman run --name mailautoconf \
--rm \ --rm \
-p "8010:80" \ -p "8010:8010" \
-v ./config:/var/www/html/config \ -v ./config:/mailautoconf/config \
pswilde/mailautoconf pswilde/mailautoconf

View file

@ -1,3 +0,0 @@
<?php
echo "No Db...yet.";
?>

View file

@ -1,57 +0,0 @@
<?php
// this class starts the whole thing going.
class Init {
public function start (){
// define a constant for checking later on
define("LETSGO",true);
// require the Load class which also imports the Core class
require("init/loader.php");
// Not sure if we're using a database yet, but leaving this here.
//require("db/db.php");
// Get the config
self::get_config();
// A Session may not be necessary as this is fundamentally an API
//Core::StartSession();
// Continue and load the requested page
$loader = new Loader();
$loader->request_page();
}
private function get_config(){
// parse the default config file for default values
$default_config = parse_ini_file(Core::root_dir()."/default-config/config.default.ini", true);
// define the custom config file location
$config_file = Core::root_dir()."/config/config.ini";
$config = array();
if (file_exists($config_file)) {
// if a custom config file exists then parse that file too
$config = parse_ini_file($config_file, true);
}
// merge the default config with the custom config
Core::$Config = array_merge($default_config,$config);
Core::$Config["PrimaryDomain"] = Core::$Config["Domain"][0];
// parse the default services file for default values
$default_services = parse_ini_file(Core::root_dir()."/default-config/services.default.ini", true);
// define the custom services file location
$services_file = Core::root_dir()."/config/services.ini";
$services = array();
if (file_exists($services_file)) {
// if a custom config file exists then parse that file too
$services = parse_ini_file($services_file, true);
}
// merge the default config with the custom config
// using replace recursive as the config file contains arrays itself
Core::$Config["Services"] = array_replace_recursive($default_services,$services);
// get the current git commit, if it exists. For testing
Core::$Config["CommitID"] = Core::get_current_git_commit();
}
}

View file

@ -1,77 +0,0 @@
<?php class Core {
public static $Config;
public const VERSION = "0.0.7";
public static $CurrentPage;
public static function root_dir(){
return $_SERVER['DOCUMENT_ROOT'];
}
public static function get_post_data(){
// Gets the POST request into an array
$data = [];
foreach($_POST as $key=>$value){
$data[$key] = $value;
}
return $data;
}
public static function get_get_data(){
// Gets the GET request into an array
$data = [];
foreach($_GET as $key=>$value){
$data[$key] = $value;
}
return $data;
}
public static function random_string($length = 10) {
// Generates a random string - unused currently
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
public static function start_session(){
// Starts a session, unused currently
session_start();
}
public static function end_session($redirect = true){
// Unset all of the session variables
$_SESSION = array();
setcookie("user_session", "", time() - 3600);
// Destroy the session.
session_destroy();
if($redirect){
header("location: /?e=LogoutSuccess");
}
}
public static function get_current_git_commit( $branch='master' ) {
// Gets the current git commit ID - for testing
$gitref = sprintf( self::root_dir().'/../.git/refs/heads/%s', $branch );
if ( file_exists($gitref) && $hash = file_get_contents( $gitref ) ) {
return trim($hash);
} else {
return false;
}
}
public static function full_url(){
// Gets the full requested URL
if(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
$addr = "https";
} else {
$addr = "http";
}
// Here append the common URL characters.
$addr .= "://";
// Append the host(domain name, ip) to the URL.
$addr .= $_SERVER['HTTP_HOST'];
// Append the requested resource location to the URL
$addr .= $_SERVER['REQUEST_URI'];
// Return the address
return $addr;
}
}

View file

@ -1,34 +0,0 @@
<?php
class Errors {
public function throw_error($err){
header('Content-Type: application/json'); // <-- header declaration
$error = false;
// Some Saved error messages - more to be added
switch ($err) {
case "NotFound":
$error = new ErrorMessage("Error","404","Not Found");
break;
case "Unauthorized":
$error = new ErrorMessage("Error","402","Unauthorized");
break;
default:
$error = new ErrorMessage("Error","500","Internal Error");
break;
}
// Output error in JSON format
echo json_encode($error, true); // <--- encode
}
}
class ErrorMessage {
public $error;
public $code;
public $message;
public $commit;
public function __construct($err,$code,$msg){
$this->error = $err;
$this->code = $code;
$this->message = $msg;
$this->url = Core::$CurrentPage;
$this->commit = Core::$Config["CommitID"];
}
}

View file

@ -1,44 +0,0 @@
<?php
// require all necessary files
require ("core.php");
require ("user.php");
require ("responder.php");
require ("errors.php");
class Loader {
public function request_page(){
// Check if user is authenticated and go to the relevant section
// Currently no authentication is in place so should always be true
if (User::is_authenticated()){
$this->go_to_page(true);
} else {
$this->go_to_page(false);
}
}
public function go_to_page($authenticated) {
switch ($authenticated) {
case false:
require(Core::root_dir()."/public/unauthorized.php");
break;
default:
$p = $this->get_page_name();
if(substr($p,0,1) == "/") {
// Remove first slash if exists
Core::$CurrentPage = substr($p,1);
} else {
Core::$CurrentPage = $p;
}
require_once(Core::root_dir()."/public/respond.php");
break;
}
}
public function get_page_name(){
$uri = Core::get_get_data();
$page = "/none";
if(isset($uri["path"])){
$page = parse_url($uri["path"]);
$page = $page["path"];
}
return $page;
}
}

View file

@ -1,187 +0,0 @@
<?php
class Responder {
private $Response;
public function show_response(){
// get the response detailed by the url requested
$response = $this->get_response();
if ($response){
// send response
$this->send_response($response);
} else {
// Send error instead
$e = new Errors();
$e->throw_error("NotFound");
}
}
private function send_response($response){
switch ($response->content_type){
case "json":
header('Content-Type: application/json');
// Send json encoded response
echo json_encode($response);
break;
case "ms-json":
header('Content-Type: application/json');
// Send json encoded response
// This is currently an undocumented file from Microsoft so it's not ready yet
echo json_encode($response->content, JSON_UNESCAPED_UNICODE);
break;
case "xml":
header('Content-Type: application/xml');
include ($response->content);
break;
}
}
private function get_response(){
$resp = false;
// Handle the requested URL, using as many known autoconfiguration urls as possible
switch (strtolower(Core::$CurrentPage)){
case "get/test":
$resp = $this->dummy_response();
break;
case "get/all":
$resp = $this->all_urls();
break;
case "mail/autoconfig.xml":
case "mail/config-v1.1.xml":
$resp = $this->moz_auto_config();
break;
case "autodiscover/autodiscover.xml":
$resp = $this->ms_autodiscover();
break;
case "autodiscover/autodiscover.json":
$resp = $this->ms_autodiscover_json();
break;
case "get/config":
$resp = $this->get_config();
break;
case "none":
case "test":
case "home":
case "root":
$resp = $this->get_test_working();
break;
default:
break;
}
return $resp;
}
private function get_config(){
$response = new Response();
$response->message = "Here's your config...";
foreach (Core::$Config as $k => $v){
$response->content[$k] = $v;
}
return $response;
}
private function get_username($service,$email_address) {
$username = "%EMAILADDRESS%";
if(!$service["UsernameIsFQDN"]) {
preg_match("/^[^@]+/",$email_address,$matches);
if (count($matches) > 0){
$username = $matches[0];
}
} else if ($service["RequireLogonDomain"]) {
$username = preg_replace("/[^@]+$/",Core::$Config["LogonDomain"],$email_address,1);
}
return $username;
}
private function all_urls(){
$response = new Response();
// Not really useful, unless some lovely app developers want to parse it for their app :)
// TODO:: Will work out a better message later
$response->message = "All URLs Requested";
// Cycle through each service and add to payload
foreach (Core::$Config["Services"] as $key => $service){
if (!$service["Enabled"]) {
continue;
}
$response->content[$key] = $service;
}
return $response;
}
private function moz_auto_config(){
// The default Thunderbird or Evolution autoconfig.xml file
$response = new Response();
$response->content_type = "xml";
$response->content = "public/autoconfig.php";
return $response;
}
private function ms_autodiscover(){
// The default Microsoft Autodiscover.xml file
$response = new Response();
$response->content_type = "xml";
$response->content = "public/autodiscover.php";
return $response;
}
private function ms_autodiscover_json(){
// The new Microsoft Autodiscover.json file - undocumented
$response = new Response();
$response->content_type = "ms-json";
if (strtolower($_GET['Protocol']) == 'autodiscoverv1') {
$response->content = new MSAutodiscoverJSONResponse();
$response->content->Protocol = "AutodiscoverV1";
$response->content->Url = Core::$Config["BaseURL"] . "/Autodiscover/Autodiscover.xml";
} else {
$response->content = new MSAutodiscoverJSONError();
http_response_code(400);
$response->headers_set = true;
$response->content->ErrorCode = "InvalidProtocol";
$response->content->ErrorMessage = "The given protocol value '" . $_GET['Protocol'] . "' is invalid. Supported values are 'AutodiscoverV1'";
}
return $response;
}
private function dummy_response(){
// Generate a dummy response for testing
$response = new Response();
$response->message = "OK, here's some scrumptious data! Enjoy!";
$response->content = array("data" => array("some_data" => "Ohhhhhmmmm nom nom nom nom nom nom",
"extra_data" => array("garnish" => "buuuuuuuuuuurp")),
"more_data" => "yuuuuuum yum yum yum");
return $response;
}
private function get_test_working(){
// Generate a dummy response for testing
$response = new Response();
$response->message = "Success! Things are working! Please request a valid URL i.e. /mail/config-v1.1.xml";
return $response;
}
}
class Response {
public $url;
public $content_type = "json";
public $message;
// public $headers_set = false;
public $content = array();
public function __construct(){
// add requested page to response. I don't know why, but it could helpful for diagnostics at some point
// Does not happen on autoconfig.xml/autodisocver.xml/autodiscover.json files
$this->url = Core::$CurrentPage;
if (!Core::$Config["CommitID"]){
$this->version = Core::VERSION;
} else {
$this->version = "git commit ".Core::$Config["CommitID"];
}
}
}
class AutoConfig {
public function prepare_autoconfig_info() {
// TODO: Move all the code in autoconfig.php into here
return false;
}
}
class MSAutodiscoverJSONResponse {
// More work to do - handling of MS Autodiscover.json requests
public $Protocol;
public $Url;
}
class MSAutodiscoverJSONError {
public $ErrorCode;
public $ErrorMessage;
}

View file

@ -1,9 +0,0 @@
<?php
class User {
public static function is_authenticated(){
// lots of work to do here to handle authentication.
// Currently just returns true for testing purposes
// I intend to make this authenticate against the primary IMAP server
return true;
}
}

View file

@ -1,13 +0,0 @@
; Sample config.ini file.
; Copy this file to "config/config.ini" and adjust the settings to your requirements
; The URL of this application
BaseURL = "https://autoconfig.example.com"
; Set the email domains for use with this service. The first one is primary.
; each will need their own DNS A record for autoconfig.domain.name
Domain[] = example.com
Domain[] = example2.com
; If you use a different domain to authenticate with, enter it here
LogonDomain = example.local

View file

@ -1,116 +0,0 @@
; The Incoming mail Server Config
[InMail]
; Enable this service
Enabled = true
; Mail Type, i.e. IMAP, POP3
Type = "IMAP"
; Your IMAP server
Server = "imap.example.com"
; Your IMAP port
Port = 993
; The socket type : SSL, STARTTLS, or NONE
SocketType = SSL
; Use Secure Password Authentication
SPA = false
; Change to true if you need the domain/logondomain to form part of the username
UsernameIsFQDN = false
; Do you need to authenticate to your mail server? You should! so this should be false!
NoAuthRequired = false
; Authentication type,
;"password-cleartext" : Send password in the clear
; (dangerous, if SSL isn't used either).
; AUTH PLAIN, LOGIN or protocol-native login.
;"password-encrypted" : A secure encrypted password mechanism.
; Can be CRAM-MD5 or DIGEST-MD5. Not NTLM.
;"NTLM": Use NTLM (or NTLMv2 or successors),
; the Windows login mechanism.
Authentication = password-cleartext
; The Outgoing mail server config
[OutMail]
; Enable this service
Enabled = true
; Mail type, likely to only be SMTP
Type = "SMTP"
; Your SMTP server
Server = "smtp.example.com"
; Your SMTP port
Port = 465
; The socket type : SSL, STARTTLS or NONE
SocketType = SSL
; See InMail > Authentication
Authentication = password-cleartext
; Use Secure Password Authentication
SPA = false
; Change to true if you need the domain/logondomain to form part of the username
UsernameIsFQDN = false
; Do you need to authenticate to your mail server? You should! so this should be false!
NoAuthRequired = false
; Use POP Authentication? You probably shouldn't be.
POPAuth = false
; This setting is here to limit errors, I'm not sure what it does yet.
SMTPLast = false
; Currently not implemented, see https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
[Calendar]
; Disable this service
Enabled = false
Server = "https://example.com/remote.php/dav/"
Port = 443
Type = CalDAV
Authentication = http-basic
UsernameIsFQDN = false
; Currently not implemented, see https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
[AddressBook]
; Disable this service
Enabled = false
Server = "https://example.com/remote.php/dav/"
Port = 443
Type = CardDAV
Authentication = http-basic
UsernameIsFQDN = false
; Currently not implemented, see https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
[WebMail]
; Disable this service
Enabled = false
Server = https://mail.example.com
UsernameDivID = "username"
UsernameDivName = "username"
PasswordDivName = "password"
SubmitButtonID = "submit"
SubmitButtonName = "submit"
UsernameIsFQDN = false
; In theory, additional custom services can be configured and will be displayed with
; their options on the /get/all URL of this service. The third-party clients would need to
; check this service as part of their development for this to work
; Will not be shown in autodiscover.xml/json or config-v1.1.xml/autoconfig.xml
; i.e Nextcloud - ideally a nextcloud client could check autoconfig for this URL for ease of set up
;[Nextcloud]
;Server = https://nextcloud.example.com

View file

@ -1,5 +0,0 @@
<?php
// entry point - inport and run the public index.php file
include("core/init.php");
$b = new Init();
$b->start();

View file

@ -1,66 +0,0 @@
<?php
// Get some core information to help with generation.
$services = Core::$Config["Services"];
$data = Core::get_get_data();
if (isset($data["emailaddress"])) {
$email_address = $data["emailaddress"];
}
// The below link has config-v1.1.xml information
// https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat
?>
<clientConfig version="1.1">
<emailProvider id="<?php echo Core::$Config["PrimaryDomain"]?>">
<?php foreach (Core::$Config["Domain"] as $domain){ ?>
<domain><?php echo $domain; ?></domain>
<?php } ?>
<displayName>%EMAILADDRESS%</displayName>
<?php if($services["InMail"]&& $services["InMail"]["Enabled"]){
$service = $services["InMail"]; ?>
<incomingServer type="<?php echo strtolower($service["Type"]);?>">
<hostname><?php echo $service["Server"];?></hostname>
<port><?php echo $service["Port"];?></port>
<socketType><?php echo $service["SocketType"];?></socketType>
<username><?php echo $this->get_username($service,$email_address); ?></username>
<authentication><?php echo $service["Authentication"];?></authentication>
</incomingServer>
<?php }
if($services["OutMail"]&& $services["OutMail"]["Enabled"]){
$service = $services["OutMail"]; ?>
<outgoingServer type="<?php echo strtolower($service["Type"]);?>">
<hostname><?php echo $service["Server"];?></hostname>
<port><?php echo $service["Port"];?></port>
<socketType><?php echo $service["SocketType"];?></socketType>
<username><?php echo $this->get_username($service,$email_address);?></username>
<authentication><?php echo $service["Authentication"];?></authentication>
</outgoingServer>
<?php }
if ($services["AddressBook"] && $services["AddressBook"]["Enabled"]) {
$service = $services["AddressBook"]; ?>
<addressBook type="<?php echo strtolower($service["Type"]); ?>">
<username><?php echo $this->get_username($service,$email_address);?></username>
<authentication><?php echo $service["Authentication"];?></authentication>
<serverURL><?php echo $service["Server"];?></serverURL>
</addressBook>
<?php }
if ($services["Calendar"] && $services["Calendar"]["Enabled"]){
$service = $services["Calendar"] ;?>
<calendar type="<?php echo strtolower($service["Type"]);?>">
<username><?php echo $this->get_username($service,$email_address);?></username>
<authentication><?php echo $service["Authentication"];?></authentication>
<serverURL><?php echo $service["Server"];?></serverURL>
</calendar>
<?php }
if ($services["WebMail"] && $services["WebMail"]["Enabled"]) {
$service = $services["WebMail"]; ?>
<webMail>
<loginPage url="<?php echo $service["Server"];?>" />
<loginPageInfo url="<?php echo $service["Server"];?>">
<username><?php echo $this->get_username($service,$email_address);?></username>
<usernameField id="<?php echo $service["UsernameDivID"];?>" name="<?php echo $service["UsernameDivName"];?>" />
<passwordField name="<?php echo $service["PasswordDivName"];?>" />
<loginButton id="<?php echo $service["SubmitButtonID"];?>" name="<?php echo $service["SubmitButtonName"];?>"/>
</loginPageInfo>
</webMail>
<?php } ?>
</emailProvider>
</clientConfig>

View file

@ -1,52 +0,0 @@
<?php
$conf = Core::$Config["Services"];
//get raw POST data so we can extract the email address
$data = file_get_contents("php://input");
preg_match("/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $data, $matches);
// Example POST Request (sent from client) :
// <?xml version="1.0" \?\>
// <Autodiscover xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
// <Request>
// <EMailAddress>your@email.address</EMailAddress>
// <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
// </Request>
// </Autodiscover>
echo '<?xml version="1.0" encoding="utf-8" ?>';?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
<Account>
<AccountType>email</AccountType>
<Action>settings</Action>
<?php if ($conf["InMail"] && $conf["InMail"]["Enabled"]){
$in = $conf["InMail"];?>
<Protocol>
<Type><?php echo $in["Type"];?></Type>
<Server><?php echo $in["Server"];?></Server>
<Port><?php echo $in["Port"];?></Port>
<DomainRequired><?php echo Core::$Config["RequireAuthDomain"] ? "on" : "off";?></DomainRequired>
<LoginName><?php echo isset($matches[1]) ? $matches[1] : false ; ?></LoginName>
<SPA><?php echo $in["SPA"] ? "on" : "off";?></SPA>
<SSL><?php echo $in["SocketType"] == "SSL" ? "on" : "off";?></SSL>
<AuthRequired><?php echo $in["NoAuthRequired"] ? "off" : "on";?></AuthRequired>
</Protocol>
<?php }
if ($conf["OutMail"]&& $conf["OutMail"]["Enabled"]) {
$out = $conf["OutMail"];?>
<Protocol>
<Type><?php echo $out["Type"];?></Type>
<Server><?php echo $out["Server"];?></Server>
<Port><?php echo $out["Port"];?></Port>
<DomainRequired><?php echo Core::$Config["RequireAuthDomain"] ? "on" : "off";?></DomainRequired>
<LoginName><?php echo isset($matches[1]) ? $matches[1] : false ; ?></LoginName>
<SPA><?php echo $in["SPA"] ? "on" : "off";?></SPA>
<Encryption><?php echo $in["SocketType"];?></Encryption>
<AuthRequired><?php echo $in["NoAuthRequired"] ? "off" : "on";?></AuthRequired>
<UsePOPAuth><?php echo $in["POPAuth"] ? "on" : "off";?></UsePOPAuth>
<SMTPLast><?php echo $in["SMTPLast"] ? "on" : "off";?></SMTPLast>
</Protocol>
<?php } ?>
</Account>
</Response>
</Autodiscover>

View file

@ -1,5 +0,0 @@
<?php
//return the json response :
$e = new Errors();
$e->throw_error("NotFound");
exit();

View file

@ -1,5 +0,0 @@
<?php
//return the json response :
$e = new Responder();
$e->show_response();
exit();

View file

@ -1,5 +0,0 @@
<?php
//return the json response :
$e = new Errors();
$e->throw_error("Unauthorized");
exit();

View file

@ -1,4 +0,0 @@
#!/usr/bin/env bash
a2enmod rewrite
service apache2 stop
exec bash /entrypoint.sh

View file

@ -1,11 +0,0 @@
#!/usr/bin/env bash
podman run --name mailautoconf-test \
--rm \
-p "8010:80" \
-v ./src:/var/www/html/ \
-v ./config:/var/www/html/config \
-v ./test-entry.sh:/test-entry.sh \
-v ./entrypoint.sh:/entrypoint.sh \
--entrypoint "/bin/bash" \
php:7.4-apache \
/test-entry.sh