geenforce: HTTPS payload delivery (blob store + endpoint)

This commit is contained in:
2026-07-21 10:10:59 -04:00
parent 844a28111a
commit 38c0f0395c
8 changed files with 268 additions and 6 deletions

View File

@@ -8,9 +8,10 @@ Two audiences:
collector's managed-token pattern (X-API-Key or Bearer PAT).
"""
import os
from functools import wraps
from flask import Blueprint, request, Response
from flask import Blueprint, request, Response, send_file
from flask_jwt_extended import jwt_required
from sqlalchemy.exc import IntegrityError
@@ -23,7 +24,7 @@ SHAREROOT_SETTING = 'geenforce_share_root'
from ..models import (
ManifestScope, ManifestEntry, ManifestPublishedVersion,
ManifestEnforcementReport, ManifestPayload, ENTRY_TYPES, PHASES,
ManifestEnforcementReport, ManifestPayload, ManifestBlob, ENTRY_TYPES, PHASES,
)
from ..serializer import scope_to_manifest, entry_to_dict
from ..importer import build_entry, populate_entry
@@ -98,6 +99,48 @@ def get_manifest():
'X-Manifest-Version': str(published.versionnumber)})
# -- client payload download (share-less installer delivery) ------------------
@geenforce_bp.route('/payload/<sha256>', methods=['GET'])
@require_fetch_token
def get_payload(sha256):
"""Serve a payload blob by content hash over HTTPS.
Lets share-less (Intune/local-account) PCs pull installers the manifest
references without SMB. Sources: the content-addressed blob store (large
http payloads) first, then an inline DB payload with this hash. The client
re-verifies the sha256, so the hash IS the integrity guarantee. ETag = the
hash (content is immutable).
"""
sha = (sha256 or '').strip().lower()
if len(sha) != 64 or any(c not in '0123456789abcdef' for c in sha):
return error_response(ErrorCodes.VALIDATION_ERROR, 'bad sha256',
http_code=400)
etag = f'"{sha}"'
if request.headers.get('If-None-Match') == etag:
return Response(status=304, headers={'ETag': etag})
blob = db.session.get(ManifestBlob, sha)
if blob and os.path.isfile(service.blob_path(sha)):
response = send_file(
service.blob_path(sha),
mimetype=blob.contenttype or 'application/octet-stream',
as_attachment=True, download_name=blob.filename)
response.headers['ETag'] = etag
return response
inline = ManifestPayload.query.filter_by(payloadsha256=sha).first()
if inline:
return Response(
inline.payloadbytes,
mimetype=inline.contenttype or 'application/octet-stream',
headers={'ETag': etag,
'Content-Disposition': f'attachment; filename="{inline.filename}"'})
return error_response(ErrorCodes.NOT_FOUND, 'No payload for that hash',
http_code=404)
# -- client reporting (observed state) ----------------------------------------
@geenforce_bp.route('/report', methods=['POST'])