Compare commits
21 commits
ef04c8a17a
...
3c972dd34e
Author | SHA1 | Date | |
---|---|---|---|
3c972dd34e | |||
7f8e95692c | |||
580de6c37d | |||
c2b818ecb8 | |||
6ab3e1f76b | |||
d6aec92545 | |||
da722c9781 | |||
be1d8d74f1 | |||
3165c90205 | |||
3be342b2f9 | |||
4ed1a3ec37 | |||
8a2fb1f269 | |||
f5bbf49fd1 | |||
3a45e551a5 | |||
4411a0aaf1 | |||
1e27206820 | |||
d139c1f2fc | |||
a3bc938449 | |||
7342c1ccda | |||
0c3c234520 | |||
22b9c8c0bd |
13 changed files with 247 additions and 35 deletions
20
README.MD
20
README.MD
|
@ -1,11 +1,11 @@
|
|||
# DAVDiscover - a simple, configurable autodiscover service for distributed and self-hosted groupware services.
|
||||
## What is DAVDiscover?
|
||||
DAVDiscover is a self-hosted service which provides IMAP, SMTP, CalDAV, CardDav, etc
|
||||
# MailAutoConf - a simple, configurable autodiscover service for distributed and self-hosted groupware services.
|
||||
## What is MailAutoConf?
|
||||
MailAutoConf is a self-hosted service which provides IMAP, SMTP, CalDAV, CardDav, etc
|
||||
URLs to authenticated clients for ease in set up on mobile devices and also desktop/laptop computers.
|
||||
|
||||
## What ~~does~~ will DAVDiscover do?
|
||||
DAVDiscover is currently in _very_ early stages, with a _very_ limited set of features.
|
||||
My hope for DAVDiscover is to mimic the AutoDiscover service found in Microsoft Exchange services,
|
||||
## What ~~does~~ will MailAutoConf do?
|
||||
MailAutoConf is currently in _very_ early stages, with a _very_ limited set of features.
|
||||
My hope for MailAutoConf is to mimic the AutoDiscover service found in Microsoft Exchange services,
|
||||
but with the intent of providing a set of URLS for each service which may be self-hosted and/or distributed,
|
||||
primary IMAP, SMTP, CalDAV and CardDAV URLS, but hopefully more services can be added in the future.
|
||||
|
||||
|
@ -15,7 +15,7 @@ Getting a set up like this configured on a mobile device is fairly involved for
|
|||
There are many points where set up configuration mistakes can happen, leading to service outage for a user, and the difficult job of
|
||||
the IT consultant trying to talk the user through setting the device up over the phone.
|
||||
|
||||
DAVDiscover intends to patch this problem by providing the URLS and information (Port numbers, SSL/TLS type, domain name, etc.) for each service
|
||||
MailAutoConf intends to patch this problem by providing the URLs and information (Port numbers, SSL/TLS type, domain name, etc.) for each service
|
||||
in JSON format allowing for the connecting device to automatically set up this information on the device.
|
||||
|
||||
## What problems do I expect?
|
||||
|
@ -27,13 +27,13 @@ In the perfect world, this service starts to look so fantastic that mobile devic
|
|||
in their own code as an Account Type (i.e. ActiveSync, Office365, iCloud, IMAP, etc. are all already there), but I'm not sure if I see that happening just yet.
|
||||
|
||||
### Another problem is authentication.
|
||||
I'd like all clients to authenticate to the DAVDiscover service, but where do we get that authentication from?
|
||||
We could have local accounts on the DAVDiscover server obviously, but I don't think this feels "fluent" enough. Maybe, using the primary IMAP server address, we could do an authentication request and if that succeeds the login is accepted and DAVDiscover information is sent.
|
||||
I'd like all clients to authenticate to the MailAutoConf service, but where do we get that authentication from?
|
||||
We could have local accounts on the MailAutoConf server obviously, but I don't think this feels "fluent" enough. Maybe, using the primary IMAP server address, we could do an authentication request and if that succeeds the login is accepted and MailAutoConf information is sent.
|
||||
|
||||
### More problems regarding authentication.
|
||||
As we're intended to be used for self-hosted, distributed services, each service may have different usernames and passwords.
|
||||
This means there will have to be some sort of manual credential entry for each service.
|
||||
I am less concerned with this issue as it currently isn't really in the scope of DAVDiscover to handle this - the goal is to provide the core information (URL, Ports, etc.) not the credentials to log in. I of course want to make the experience as helpful as possible though, so I'll deal with any features surrounding this when I can.
|
||||
I am less concerned with this issue as it currently isn't really in the scope of MailAutoConf to handle this - the goal is to provide the core information (URL, Ports, etc.) not the credentials to log in. I of course want to make the experience as helpful as possible though, so I'll deal with any features surrounding this when I can.
|
||||
|
||||
## When will it be ready for production?
|
||||
Well, not yet.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
version: '3.3'
|
||||
services:
|
||||
davdiscover:
|
||||
container_name: davdiscover
|
||||
mailautoconf:
|
||||
container_name: mailautoconf
|
||||
ports:
|
||||
- '8010:80'
|
||||
volumes:
|
||||
- './config:/var/www/html/config'
|
||||
image: pswilde/davdiscover
|
||||
image: pswilde/mailautoconf
|
||||
|
|
11
examples/dashboard.html
Normal file
11
examples/dashboard.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DAVDiscover Dashboard Example</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>This is to show the basic output of DAVDiscover, displaying the first few URLs</p>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
podman run --name davdiscover \
|
||||
podman run --name mailautoconf \
|
||||
--rm \
|
||||
-p "8010:80" \
|
||||
-v ./config:/var/www/html/config \
|
||||
pswilde/davdiscover
|
||||
pswilde/mailautoconf
|
||||
|
|
|
@ -19,9 +19,6 @@ class Loader {
|
|||
break;
|
||||
default:
|
||||
$p = $this->get_page_name();
|
||||
if (substr($p,0,6) != "/admin") {
|
||||
header('Content-Type: application/json'); // <-- header declaration
|
||||
}
|
||||
if(substr($p,0,1) == "/") {
|
||||
Core::$CurrentPage = substr($p,1);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
class Responder {
|
||||
private $Response;
|
||||
public function show_response(){
|
||||
// get the response detailed by the url requested
|
||||
$response = $this->get_response();
|
||||
|
@ -13,8 +14,24 @@ class Responder {
|
|||
}
|
||||
}
|
||||
private function send_response($response){
|
||||
// Send json encoded response
|
||||
echo json_encode($response, true);
|
||||
switch ($response->content_type){
|
||||
case "json":
|
||||
header('Content-Type: application/json');
|
||||
// Send json encoded response
|
||||
echo json_encode($response, true);
|
||||
break;
|
||||
case "ms-json":
|
||||
header('Content-Type: application/json');
|
||||
// Send json encoded response
|
||||
echo json_encode($response->content, true);
|
||||
break;
|
||||
case "xml":
|
||||
header('Content-Type: application/xml');
|
||||
include ($response->content);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private function get_response(){
|
||||
$resp = false;
|
||||
|
@ -25,8 +42,16 @@ class Responder {
|
|||
case "get/all":
|
||||
$resp = $this->all_urls();
|
||||
break;
|
||||
case "get/select":
|
||||
$resp = $this->selection();
|
||||
case "mail/config-v1.1.xml":
|
||||
$resp = $this->moz_auto_config();
|
||||
break;
|
||||
case "autodiscover/autodiscover.xml":
|
||||
case "Autodiscover/Autodiscover.xml":
|
||||
$resp = $this->ms_autodiscover();
|
||||
break;
|
||||
case "autodiscover/autodiscover.json": //?Email=psw%40wilde.cloud&Protocol=Autodiscoverv1&RedirectCount=1"
|
||||
case "Autodiscover/Autodiscover.json":
|
||||
$resp = $this->ms_autodiscover_json();
|
||||
break;
|
||||
case "none":
|
||||
case "test":
|
||||
|
@ -40,8 +65,6 @@ class Responder {
|
|||
return $resp;
|
||||
}
|
||||
private function all_urls(){
|
||||
|
||||
// This would be the default request from, say, an app.
|
||||
$response = new Response();
|
||||
|
||||
// TODO:: Will work out a better message later
|
||||
|
@ -49,23 +72,36 @@ class Responder {
|
|||
|
||||
// Cycle through each service and add to payload
|
||||
foreach (Core::$Config["Services"] as $key => $service){
|
||||
$response->payload[$key] = $service;
|
||||
$response->content[$key] = $service;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
private function selection(){
|
||||
private function moz_auto_config(){
|
||||
$response = new Response();
|
||||
$response->message = "Not Implemented";
|
||||
$uri = Core::full_url();
|
||||
$response->payload = parse_url($uri);
|
||||
$response->content_type = "xml";
|
||||
$response->content = "public/autoconfig.php";
|
||||
return $response;
|
||||
}
|
||||
private function ms_autodiscover(){
|
||||
$response = new Response();
|
||||
$response->content_type = "xml";
|
||||
$response->content = "public/autodiscover.php";
|
||||
return $response;
|
||||
}
|
||||
private function ms_autodiscover_json(){
|
||||
$response = new Response();
|
||||
$response->content_type = "ms-json";
|
||||
$response->content = new MSAutodiscoverJSONResponse();
|
||||
$response->content->Protocol = "AutodiscoverV1";
|
||||
$response->content->Url = Core::$Config["BaseURL"] . "/Autodiscover/Autodiscover.xml";
|
||||
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->payload = array("data" => array("some_data" => "Ohhhhhmmmm nom nom nom nom nom nom",
|
||||
$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;
|
||||
|
@ -79,8 +115,9 @@ class Responder {
|
|||
}
|
||||
class Response {
|
||||
public $url;
|
||||
public $content_type = "json";
|
||||
public $message;
|
||||
public $payload = array();
|
||||
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
|
||||
$this->url = Core::$CurrentPage;
|
||||
|
@ -92,3 +129,7 @@ class Response {
|
|||
|
||||
}
|
||||
}
|
||||
class MSAutodiscoverJSONResponse {
|
||||
public $Protocol;
|
||||
public $Url;
|
||||
}
|
||||
|
|
84
src/public/autoconfig.php
Normal file
84
src/public/autoconfig.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
$conf = Core::$Config["Services"];
|
||||
$data = Core::get_get_data();
|
||||
$email_provided = false;
|
||||
$display_name = false;
|
||||
$emailaddress = false;
|
||||
if ($data["emailaddress"]) {
|
||||
$email_address = $data["emailaddress"];
|
||||
$display_name = $email_address;
|
||||
$email_provided = true;
|
||||
} else if ($data["path"]) {
|
||||
$query = parse_url($data["path"]);
|
||||
$email_address = explode("=",$query["query"]);
|
||||
if ($email_address[0] == "emailaddress") {
|
||||
$email_address = $email[1];
|
||||
$email_provided = true;
|
||||
$display_name = $email_address;
|
||||
}
|
||||
}
|
||||
if ($email_provided) {
|
||||
if(!Core::$Config["RequireAuthDomain"]) {
|
||||
$email_address = str_ireplace("@".Core::$Config["Domain"],"",$email_address);
|
||||
} else if (Core::$Config["LogonDomain"]) {
|
||||
$email_address = str_ireplace(Core::$Config["Domain"],Core::$Config["LogonDomain"],$email_address);
|
||||
}
|
||||
}
|
||||
|
||||
// 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["Domain"]?>">
|
||||
<domain><?php echo Core::$Config["Domain"]?></domain>
|
||||
<displayName><?php echo $email_provided ? $display_name : "%EMAILADDRESS%" ;?></displayName>
|
||||
<?php if($conf["InMail"]){
|
||||
$in = $conf["InMail"]; ?>
|
||||
<incomingServer type="<?php echo strtolower($in["Type"]);?>">
|
||||
<hostname><?php echo $in["Server"];?></hostname>
|
||||
<port><?php echo $in["Port"];?></port>
|
||||
<socketType><?php echo $in["SocketType"];?></socketType>
|
||||
<username><?php echo $email_provided ? $email_address : "%EMAILADDRESS%";?></username>
|
||||
<authentication><?php echo $in["Authentication"];?></authentication>
|
||||
</incomingServer>
|
||||
<?php }
|
||||
if($conf["OutMail"]){
|
||||
$out = $conf["OutMail"]; ?>
|
||||
<outgoingServer type="<?php echo strtolower($out["Type"]);?>">
|
||||
<hostname><?php echo $out["Server"];?></hostname>
|
||||
<port><?php echo $out["Port"];?></port>
|
||||
<socketType><?php echo $out["SocketType"];?></socketType>
|
||||
<username><?php echo $email_provided ? $email_address : "%EMAILADDRESS%";?></username>
|
||||
<authentication><?php echo $out["Authentication"];?></authentication>
|
||||
</outgoingServer>
|
||||
<?php }
|
||||
if ($conf["AddressBook"]) {
|
||||
$card = $conf["AddressBook"]; ?>
|
||||
<addressBook type="<?php echo strtolower($card["Type"]); ?>">
|
||||
<username><?php echo $email_provided ? $email_address : "%EMAILADDRESS%";?></username>
|
||||
<authentication><?php echo $card["Authentication"] ? $card["Authentication"] : "http-basic" ;?></authentication>
|
||||
<serverURL><?php echo $card["Server"];?></serverURL>
|
||||
</addressBook>
|
||||
<?php }
|
||||
if ($conf["Calendar"]){
|
||||
$cal = $conf["Calendar"] ;?>
|
||||
<calendar type="<?php echo strtolower($cal["Type"]);?>">
|
||||
<username><?php echo $email_provided ? $email_address : "%EMAILADDRESS%";?></username>
|
||||
<authentication><?php echo $card["Authentication"] ? $card["Authentication"] : "http-basic" ;?></authentication>
|
||||
<serverURL><?php echo $card["Server"];?></serverURL>
|
||||
</calendar>
|
||||
<?php }
|
||||
if ($conf["WebMail"]) {
|
||||
$wm = $conf["WebMail"]; ?>
|
||||
<webMail>
|
||||
<loginPage url="<?php echo $wm["Server"];?>" />
|
||||
<loginPageInfo url="<?php echo $wm["Server"];?>">
|
||||
<username><?php echo $email_provided ? $email_address : "%EMAILADDRESS%";?></username>
|
||||
<usernameField id="<?php echo $wm["UsernameDivID"];?>" name="<?php echo $wm["UsernameDivName"];?>" />
|
||||
<passwordField name="<?php echo $wm["PasswordDivName"];?>" />
|
||||
<loginButton id="<?php echo $wm["SubmitButtonID"];?>" name="<?php echo $wm["SubmitButtonName"];?>"/>
|
||||
</loginPageInfo>
|
||||
</webMail>
|
||||
<?php } ?>
|
||||
</emailProvider>
|
||||
</clientConfig>
|
55
src/public/autodiscover.php
Normal file
55
src/public/autodiscover.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
$conf = Core::$Config["Services"];
|
||||
//get raw POST data so we can extract the email address
|
||||
$data = file_get_contents("php://input");
|
||||
// file_put_contents(Core::root_dir()."/xmltest", $data);
|
||||
preg_match("/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $data, $matches);
|
||||
//print_r($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>psw@wilde.cloud</EMailAddress>
|
||||
// <AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
|
||||
// </Request>
|
||||
// </Autodiscover>
|
||||
|
||||
echo '<?xml version="1.0" encoding="utf-8" ?>';?>
|
||||
<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/responseschema/2006">
|
||||
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
|
||||
<Account>
|
||||
<AccountType>email</AccountType>
|
||||
<Action>settings</Action>
|
||||
<?php if ($conf["InMail"]){
|
||||
$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 $matches[1]; ?></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"]) {
|
||||
$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 $matches[1]; ?></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>
|
|
@ -1,6 +1,13 @@
|
|||
; Sample config.ini file.
|
||||
; Copy this file to "config/config.ini" and adjust the settings to your requirements
|
||||
|
||||
; Set the base domain for use with this service
|
||||
Domain = example.com
|
||||
LogonDomain = example.local
|
||||
RequireAuthDomain = false
|
||||
|
||||
BaseURL = "https://autoconfig.example.com"
|
||||
|
||||
; Admin User configuration
|
||||
; not in use yet
|
||||
;[AdminUser]
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
[InMail]
|
||||
Type = "IMAP"
|
||||
Server = "imap.example.com"
|
||||
Protocol = "IMAP"
|
||||
Port = 993
|
||||
TLS = true
|
||||
SocketType = SSL
|
||||
Authentication = password-cleartext
|
||||
|
||||
[OutMail]
|
||||
Type = "SMTP"
|
||||
Server = "smtp.example.com"
|
||||
Protocol = "SMTP"
|
||||
Port = 465
|
||||
TLS = true
|
||||
SocketType = SSL
|
||||
Authentication = password-cleartext
|
||||
|
||||
[CalDav]
|
||||
Server = "https://caldav.example.com/etc/etc/"
|
||||
|
|
1
src/xmltest
Executable file
1
src/xmltest
Executable file
|
@ -0,0 +1 @@
|
|||
<EMailAddress>psw@wilde.cloud</EMailAddress>
|
4
test-entry.sh
Executable file
4
test-entry.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
a2enmod rewrite
|
||||
service apache2 stop
|
||||
exec apache2-foreground
|
10
test-server.sh
Normal file
10
test-server.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/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 \
|
||||
--entrypoint "/bin/bash" \
|
||||
php:7.4-apache \
|
||||
/test-entry.sh
|
Loading…
Reference in a new issue