Skip to content

Commit

Permalink
Move .well-known route to shared gen-ed package; serve from instance …
Browse files Browse the repository at this point in the history
…path; update README to document.
  • Loading branch information
liffiton committed Nov 2, 2024
1 parent 0595b66 commit e5b5bd5
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 38 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ To change the password:
flask --app codehelp setpassword [username]
```

4. (Optional) To serve files from `/.well-known` (for domain verification,
etc.), place the files in a `.well-known` directory inside the Flask
instance folder.


Running an Application
----------------------
Expand Down
7 changes: 0 additions & 7 deletions src/codehelp/.well-known/microsoft-identity-association.json

This file was deleted.

7 changes: 0 additions & 7 deletions src/codehelp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
from pathlib import Path
from typing import Any

from flask import send_from_directory
from flask.app import Flask
from flask.wrappers import Response

from gened import base

Expand Down Expand Up @@ -58,11 +56,6 @@ def create_app(test_config: dict[str, Any] | None = None, instance_path: Path |
# register app-specific charts in the admin interface
admin.register_with_gened()

# make a simple route for the .well-known directory
@app.route('/.well-known/<path:path>')
def well_known(path: Path) -> Response:
return send_from_directory('.well-known', path)

# add navbar items
app.config['NAVBAR_ITEM_TEMPLATES'].append("tutor_nav_item.html")

Expand Down
7 changes: 6 additions & 1 deletion src/gened/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@

import flask.app
from dotenv import load_dotenv
from flask import Flask, render_template
from flask import Flask, render_template, send_from_directory
from flask.wrappers import Response
from werkzeug.middleware.proxy_fix import ProxyFix

from . import (
Expand Down Expand Up @@ -207,4 +208,8 @@ def inject_auth_data() -> dict[str, Any]:
def landing() -> str:
return render_template("landing.html")

@app.route('/.well-known/<path:path>')
def well_known(path: Path) -> Response:
return send_from_directory(Path(app.instance_path) / '.well-known', path)

return app
48 changes: 25 additions & 23 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
#
# SPDX-License-Identifier: AGPL-3.0-only

import os
import tempfile
from pathlib import Path

import codehelp
import openai
import pytest
from dotenv import find_dotenv, load_dotenv

import codehelp
from gened.admin import reload_consumers
from gened.db import get_db, init_db
from gened.testing.mocks import mock_async_completion, mock_completion
Expand All @@ -26,7 +26,7 @@ def _load_env():
load_dotenv(env_file)


@pytest.fixture()
@pytest.fixture
def app(monkeypatch, request):
""" Provides an application object and by default monkey patches openai to
*not* send requests: the most common case for testing.
Expand All @@ -40,35 +40,37 @@ def app(monkeypatch, request):
monkeypatch.setattr(openai.resources.chat.Completions, "create", mock_completion(0.0))
monkeypatch.setattr(openai.resources.chat.AsyncCompletions, "create", mock_async_completion(0.0))

# Create an app and initialize the DB
db_fd, db_path = tempfile.mkstemp()
# Create a temporary app root with instance directory
with tempfile.TemporaryDirectory() as temp_dir:
instance_path = Path(temp_dir)

app = codehelp.create_app(
test_config={
'TESTING': True,
'DATABASE': db_path,
'OPENAI_API_KEY': 'invalid', # ensure an invalid API key for testing
},
instance_path=Path(db_path).absolute().parent,
)
# Create database in the instance directory
db_path = instance_path / 'test.db'

with app.app_context():
init_db()
get_db().executescript(_test_data_sql)
reload_consumers() # reload consumers from now-initialized DB
app = codehelp.create_app(
test_config={
'TESTING': True,
'DATABASE': str(db_path),
'OPENAI_API_KEY': 'invalid', # ensure an invalid API key for testing
},
instance_path=instance_path,
)

yield app
with app.app_context():
init_db()
get_db().executescript(_test_data_sql)
reload_consumers() # reload consumers from now-initialized DB

os.close(db_fd)
os.unlink(db_path)
yield app
# Directory cleanup happens automatically when the context manager exits


@pytest.fixture()
@pytest.fixture
def client(app):
return app.test_client()


@pytest.fixture()
@pytest.fixture
def runner(app):
return app.test_cli_runner()

Expand All @@ -87,6 +89,6 @@ def logout(self):
return self._client.post('/auth/logout')


@pytest.fixture()
@pytest.fixture
def auth(client):
return AuthActions(client)
53 changes: 53 additions & 0 deletions tests/test_well_known.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from pathlib import Path


def test_well_known_file(client, app):
"""Test serving an existing file from .well-known"""
# Create a test file in the instance/.well-known directory
well_known_dir = Path(app.instance_path) / '.well-known'
well_known_dir.mkdir(exist_ok=True)
test_file = well_known_dir / 'test.txt'
test_file.write_text('test content')

# Request the file
response = client.get('/.well-known/test.txt')

assert response.status_code == 200
assert response.data == b'test content'


def test_well_known_missing(client):
"""Test requesting a non-existent file from .well-known"""
response = client.get('/.well-known/nonexistent.txt')
assert response.status_code == 404


def test_well_known_subdir(client, app):
"""Test serving a file from a subdirectory in .well-known"""
# Create a test file in a subdirectory
well_known_dir = Path(app.instance_path) / '.well-known'
subdir = well_known_dir / 'subdir'
subdir.mkdir(parents=True, exist_ok=True)
test_file = subdir / 'test.txt'
test_file.write_text('subdir test content')

# Request the file
response = client.get('/.well-known/subdir/test.txt')

assert response.status_code == 200
assert response.data == b'subdir test content'


def test_well_known_traversal(client, app):
"""Test that path traversal attempts are blocked"""
# Create a file in the instance directory (parent of .well-known)
secret_file = Path(app.instance_path) / 'secret.txt'
secret_file.write_text('secret content')

# Attempt to access the file through path traversal
response = client.get('/.well-known/../secret.txt')
assert response.status_code == 404

# Verify the file exists and is readable directly from disk
assert secret_file.exists()
assert secret_file.read_text() == 'secret content'

0 comments on commit e5b5bd5

Please sign in to comment.