created uv project structure, added Docker integration, updated README.md with some general info

This commit is contained in:
Nathan Windisch 2025-03-20 03:58:59 +00:00
commit 4dd522697f
7 changed files with 100 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info
# Virtual environments
.venv

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.12

7
Dockerfile Normal file
View File

@ -0,0 +1,7 @@
FROM python:3.12-slim-bookworm
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
ADD . /app
WORKDIR /app
RUN uv sync --frozen
EXPOSE 8000
CMD ["uv", "run", "fastapi", "dev", "main.py", "--host", "0.0.0.0"]

18
README.md Normal file
View File

@ -0,0 +1,18 @@
# autodiscover-proxy
A simple proxy server used to expose domains associated with a given domain via Microsoft's AutoDiscover.svc.
## Usage
Running locally:
```bash
uv run fastapi dev main.py
```
Running in Docker:
```bash
docker run -p 8000:8000 -it git.wnd.sh/n/autodiscover-proxy
# or
docker build -t autodiscover-proxy .
docker run -p 8000:8000 -it autodiscover-proxy
```

50
main.py Normal file
View File

@ -0,0 +1,50 @@
from typing import Annotated
from fastapi import FastAPI, Query
from fastapi.responses import JSONResponse
import xml.etree.ElementTree as xml
import requests
import json
app = FastAPI()
@app.get("/{domain}")
def read_root(
domain: str,
platform: Annotated[
str | None,
Query(pattern="^default|gcc|gcc_high$")
] = "default",
):
match platform:
case "gcc_high": base_uri = "autodiscover-s.office365.us"
case "gcc": base_uri = "autodiscover-s-dod.office365.us"
case "default": base_uri = "autodiscover-s.outlook.com"
headers = { "Content-Type": "text/xml; charset=utf-8", "SOAPAction": "http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation" }
uri = f"https://{base_uri}/autodiscover/autodiscover.svc"
data = f"""<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:exm="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:ext="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<a:Action soap:mustUnderstand="1">http://schemas.microsoft.com/exchange/2010/Autodiscover/Autodiscover/GetFederationInformation</a:Action>
<a:To soap:mustUnderstand="1">{uri}</a:To>
<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
</soap:Header>
<soap:Body>
<GetFederationInformationRequestMessage xmlns="http://schemas.microsoft.com/exchange/2010/Autodiscover">
<Request>
<Domain>{domain}</Domain>
</Request>
</GetFederationInformationRequestMessage>
</soap:Body>
</soap:Envelope>
"""
response = requests.post(uri, data=data, headers=headers)
if (not response.ok): return { "error": f"Error contacting autodiscover service for {domain}" }
root = xml.fromstring(response.text)
content = [i.text for i in root[1][0][0][3]] # root/body/GetFederationInformationResponseMessage/Domains
return JSONResponse(content=content, headers={"Cache-Control": "max-age=604800, public"})

7
pyproject.toml Normal file
View File

@ -0,0 +1,7 @@
[project]
name = "autodiscover-proxy"
version = "0.1.0"
description = "A simple proxy server used to expose domains associated with a given domain via Microsoft's AutoDiscover.svc."
readme = "README.md"
requires-python = ">=3.12"
dependencies = ['fastapi[standard]', 'requests']

7
uv.lock generated Normal file
View File

@ -0,0 +1,7 @@
version = 1
requires-python = ">=3.12"
[[package]]
name = "autodiscover-proxy"
version = "0.1.0"
source = { virtual = "." }