async def store( form: ZoneCreateForm, zone_repo: ZoneRepo = Depends(ZoneRepo()), dns_server_repo: DnsServerRepo = Depends(DnsServerRepo()), http_server_repo: HttpServerRepo = Depends(HttpServerRepo()), token: TokenPayload = Depends(ScopedTo("zone:create")), ): data = only(dict(form), ["ip", "domain"]) data["domain"] = data["domain"].lower() # Make sure domain is unique if zone_repo.exists(domain=data["domain"]): abort_for_input("domain", "A Zone with that domain already exists") zone_repo.clear() if form.dns_server_id: if dns_server_repo.exists(id=form.dns_server_id): data["dns_server_id"] = dns_server_repo.results().id if form.http_server_id: if http_server_repo.exists(id=form.http_server_id): data["http_server_id"] = http_server_repo.results().id zone = zone_repo.create(data).data() return ZoneResponse(zone=zone)
async def store( form: DnsRequestCreateForm, dns_request_repo: DnsRequestRepo = Depends(DnsRequestRepo()), zone_repo: ZoneRepo = Depends(ZoneRepo()), dns_server_repo: DnsServerRepo = Depends(DnsServerRepo()), token: str = Depends(ScopedTo("dns-request:create")), ): dns_server_id = ( dns_server_repo.first_or_fail(name=form.dns_server_name.lower()).results().id ) zone = ( zone_repo.filter(literal(form.name.lower()).contains(zone_repo.label("domain"))) .first() .results() ) zone_id = zone.id if zone else None data = only( dict(form), ["name", "source_address", "source_port", "type", "protocol", "raw_request"], ) data["name"] = data["name"].lower() data["type"] = data["type"].upper() data["dns_server_id"] = dns_server_id data["zone_id"] = zone_id logger.info("[email protected] - Creating DNS Request") dns_request = dns_request_repo.create(data).data() return DnsRequestResponse(dns_request=dns_request)
async def index( http_server: str, sort_qs: SortQS = Depends(SortQS), search: str = Query(None), pagination: PaginationQS = Depends(PaginationQS), zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("zone:list")), includes: List[str] = Query(None), ): includes = only(includes, ["http_records"], values=True) # Support ability to either submit http_server.name or http_server.id as http_server_id zone_http_server_id_label = zone_repo.label("http_server_id") try: http_server = int(http_server) label = zone_http_server_id_label except ValueError: label = zone_repo.label("http_server.name") pg, items = (zone_repo.search(search).loads(includes).filter_or( label == http_server, zone_http_server_id_label.is_(None)).sort( sort_qs).paginate(pagination).includes(includes).data()) return ZonesResponse(pagination=pg, zones=items)
async def show( http_server: str, http_server_repo: HttpServerRepo = Depends(HttpServerRepo()), token: TokenPayload = Depends(ScopedTo("http-server:show")), includes: List[str] = Query(None), ): includes = only(includes, ["zones"], values=True) http_server_id_label = http_server_repo.label("id") try: http_server = int(http_server) label = http_server_id_label except ValueError: label = http_server_repo.label("name") # TODO: is this vulnerable to sql injection? item = ( http_server_repo.loads(includes) .filter(label == http_server) .first_or_fail() .includes(includes) .data() ) return HttpServerResponse(http_server=item)
async def activate( zone_id: int, zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("zone:update")), ): zone = zone_repo.get_or_fail(zone_id).update({"is_active": True}).data() return ZoneResponse(zone=zone)
async def update( user_id: int, form: UserEditForm, user_repo: UserRepo = Depends(UserRepo()), token: TokenPayload = Depends( ScopedTo("user:update", "super", satisfy="one")), ): email = getattr(form, "email", None) if email: for u in user_repo.new().all().results(): print("USER:"******"Invalid Email Address", code=422, field="email") data = only(form, ["email", "is_active", "is_superuser"]) if getattr(form, "password", None): data["hashed_password"] = hash_password(form.password) item = user_repo.new().get_or_fail(user_id).update(data).data() return UserResponse(user=item)
async def update( http_server: str, form: HttpServerCreateForm, http_server_repo: HttpServerRepo = Depends(HttpServerRepo()), token: TokenPayload = Depends(ScopedTo("http-server:update")), ): data = only(dict(form), ["name"]) data["name"] = data["name"].lower() http_server_id_label = http_server_repo.label("id") try: http_server = int(http_server) label = http_server_id_label except ValueError: label = http_server_repo.label("name") # TODO: is this vulnerable to sql injection? item = ( http_server_repo.filter(label == http_server) .first_or_fail() .update(data) .data() ) return HttpServerResponse(http_server=item)
async def update( zone_id: int, form: ZoneCreateForm, zone_repo: ZoneRepo = Depends(ZoneRepo()), dns_server_repo: DnsServerRepo = Depends(DnsServerRepo()), http_server_repo: DnsServerRepo = Depends(HttpServerRepo()), token: TokenPayload = Depends(ScopedTo("zone:update")), includes: List[str] = Query(None), ): data = only(dict(form), ["ip", "domain"]) if "domain" in data: data["domain"] = data["domain"].lower() existing_domain = zone_repo.first(domain=data["domain"]).results() if existing_domain and existing_domain.id != zone_id: abort_for_input("domain", "A Zone with that domain already exists") zone_repo.clear() if form.dns_server_id is not None: if form.dns_server_id is 0: data["dns_server_id"] = None elif dns_server_repo.exists(id=form.dns_server_id): dns_server = dns_server_repo.results() data["dns_server"] = dns_server if form.http_server_id is not None: if form.http_server_id is 0: data["http_server_id"] = None elif http_server_repo.exists(id=form.http_server_id): http_server = http_server_repo.results() data["http_server"] = http_server zone = (zone_repo.loads(includes).get_or_fail(zone_id).update( data).includes(includes).data()) return ZoneResponse(zone=zone)
async def destroy( user_id: int, user_repo: UserRepo = Depends(UserRepo()), token: TokenPayload = Depends( ScopedTo("user:create", "super", satisfy="one")), user: User = Depends(current_user), ): if user_id == user.id: abort(403, msg="Cannot deactivate self") remaining_supers = len( user_repo.filter( user_repo.label("is_superuser") == True, user_repo.label("is_active") == True, user_repo.label("id") != user_id, ).all().results()) if remaining_supers < 1: abort( 403, msg="Cannot deactivate user. No other active super users available." ) user_repo.clear() messages = [{"text": "Deactivation Succesful", "type": "success"}] if not user_repo.exists(id=user_id): return BaseResponse(messages=messages) user_repo.deactivate(user_id) return BaseResponse(messages=messages)
async def sync( api_token_repo: ApiTokenRepo = Depends(ApiTokenRepo()), dns_server_repo: DnsServerRepo = Depends(DnsServerRepo()), http_server_repo: HttpServerRepo = Depends(HttpServerRepo()), token: TokenPayload = Depends(ScopedTo("api-token:syncable")), ): if "api-token" in token.scopes or "api-token:syncable" in token.scopes: abort_for_no_server_names(token) if (len(token.payload.dns_server_name) > 0 and len(token.payload.http_server_name) > 0): dns_server = create_or_get_dns_server(token, dns_server_repo) http_server = create_or_get_http_server(token, http_server_repo) api_token_data = create_or_get_api_token_for_all_nodes( token, api_token_repo, dns_server, http_server) elif len(token.payload.dns_server_name) > 0: dns_server = create_or_get_dns_server(token, dns_server_repo) api_token_data = create_or_get_api_token_for_dns_server( token, api_token_repo, dns_server) elif len(token.payload.http_server_name) > 0: http_server = create_or_get_http_server(token, http_server_repo) api_token_data = create_or_get_api_token_for_http_server( token, api_token_repo, http_server) else: # something went wrong, should not hit raise HTTPException(403, detail="Not found") return ApiTokenResponse(api_token=api_token_data) else: raise HTTPException(403, detail="Not found")
async def login( token: TokenPayload = Depends(ScopedTo("refresh")), user: User = Depends(current_user), ): token = create_bearer_token( data={"sub": token.sub, "scopes": " ".join(token.scopes)} ) return PasswordAuthResponse(token_type="bearer", access_token=str(token))
async def activate( user_id: int, user_repo: UserRepo = Depends(UserRepo()), token: TokenPayload = Depends(ScopedTo("user:create", "super")), ): user = user_repo.get_or_fail(user_id).update({"is_active": True}).data() return UserResponse(user=user)
async def index( sort_qs: SortQS = Depends(SortQS), pagination: PaginationQS = Depends(PaginationQS), user_repo: UserRepo = Depends(UserRepo()), token: TokenPayload = Depends(ScopedTo("user:list")), ): pg, items = user_repo.sort(sort_qs).paginate(pagination).data() return UsersResponse(pagination=pg, users=items)
async def show( user_repo: UserRepo = Depends(UserRepo()), token: TokenPayload = Depends(ScopedTo("profile")), user: User = Depends(current_user), ): logger.critical("Loading user") item = user_repo.set_results(user).data() return UserResponse(user=item)
async def index( sort_qs: SortQS = Depends(SortQS), pagination: PaginationQS = Depends(PaginationQS), http_request_repo: HttpRequestRepo = Depends(HttpRequestRepo()), token: TokenPayload = Depends(ScopedTo("http-request:list")), ): pg, items = (http_request_repo.loads("http_server").sort(sort_qs).includes( "http_server").paginate(pagination).data()) return HttpRequestsResponse(pagination=pg, http_requests=items)
async def destroy( api_token_id: int, api_token_repo: ApiTokenRepo = Depends(ApiTokenRepo()), token: TokenPayload = Depends(ScopedTo("api-token:destroy")), ): messages = [{"text": "Deactivation Succesful", "type": "success"}] if not api_token_repo.exists(api_token_id): return BaseResponse(messages=messages) api_token_repo.deactivate(api_token_id) return BaseResponse(messages=messages)
async def destroy( zone_id: int, zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("zone:destroy")), ): messages = [{"text": "Deactivation Succesful", "type": "success"}] if not zone_repo.exists(zone_id): return BaseResponse(messages=messages) zone_repo.deactivate(zone_id) return BaseResponse(messages=messages)
async def show( user_id: int, user_repo: UserRepo = Depends(UserRepo()), token: TokenPayload = Depends(ScopedTo("user:show", "super")), includes: List[str] = Query(None), ): includes = only(includes, [], values=True) item = user_repo.loads(includes).get_or_fail(user_id).includes( includes).data() return UserResponse(user=item)
async def show( zone_id: int, zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("zone:show")), includes: List[str] = Query(None), ): includes = only(includes, ["dns_server", "dns_records", "http_server"], values=True) zone = zone_repo.loads(includes).get_or_fail(zone_id).includes( includes).data() return ZoneResponse(zone=zone)
async def index( sort_qs: SortQS = Depends(SortQS), pagination: PaginationQS = Depends(PaginationQS), api_token_repo: ApiTokenRepo = Depends(ApiTokenRepo()), token: TokenPayload = Depends(ScopedTo("api-token:list")), includes: List[str] = Query(None), ): includes = only(includes, ["dns_server", "http_server"], values=True) pg, items = (api_token_repo.loads(includes).strict().sort( sort_qs).paginate(pagination).includes(includes).data()) return ApiTokensResponse(pagination=pg, api_tokens=items)
async def dig( zone_id: int, zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("dns-record:list")), ): zone = zone_repo.includes("dns_records").first_or_fail( id=zone_id).results() print(zone) print(zone.dns_records) # TODO: fix method rrs = RecordParser.from_zone(zone).get_rrs() dig = DNSRecord(rr=rrs).toZone() return DnsRecordsDigResponse(dig=dig)
async def show( http_request_id: int, http_request_repo: HttpRequestRepo = Depends(HttpRequestRepo()), token: TokenPayload = Depends(ScopedTo("http-request:show")), includes: List[str] = Query(None), ): # probably a bunch of access bypasses with scopes via includes # need easy way to scope for includes includes = only(includes, ["http_server", "zone"], values=True) http_request = (http_request_repo.loads(includes).get_or_fail( http_request_id).includes(includes).data()) return HttpRequestResponse(http_request=http_request)
async def index( sort_qs: SortQS = Depends(SortQS), pagination: PaginationQS = Depends(PaginationQS), dns_server_repo: DnsServerRepo = Depends(DnsServerRepo()), token: TokenPayload = Depends(ScopedTo("dns-server:list")), search: str = Query(None), includes: List[str] = Query(None), ): includes = only(includes, ["zones"], values=True) pg, items = (dns_server_repo.loads(includes).includes(includes).search( search, searchable=["name", "id"]).paginate(pagination).data()) return DnsServersResponse(pagination=pg, dns_servers=items)
async def store( zone_id: int, form: DnsRecordForZoneCreateForm, dns_record_repo: DnsRecordRepo = Depends(DnsRecordRepo()), zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("dns-record:create")), ): zone_repo.exists(id=zone_id, or_fail=True) data = only(dict(form), ["record", "sort"]) data["zone_id"] = zone_id item = dns_record_repo.create(data).data() return DnsRecordResponse(dns_record=item)
async def show( api_token_id: int, api_token_repo: ApiTokenRepo = Depends(ApiTokenRepo()), token: TokenPayload = Depends(ScopedTo("api-token:read")), includes: List[str] = Query(None), ): includes = only(includes, ["dns_server", "http_server"], values=True) if (not api_token_repo.loads(includes).strict().includes(includes).exists( api_token_id)): raise HTTPException(404, detail="Not found") api_token = api_token_repo.data() return ApiTokenResponse(api_token=api_token)
async def store( form: HttpServerCreateForm, http_server_repo: HttpServerRepo = Depends(HttpServerRepo()), token: TokenPayload = Depends(ScopedTo("http-server:create")), ): if http_server_repo.exists(name=form.name.lower()): abort_for_input("name", "Server name already taken") data = only(dict(form), ["name"]) data["name"] = data["name"].lower() item = http_server_repo.create(data).data() return HttpServerResponse(http_server=item)
async def store( form: ApiTokenCreateForm, api_token_repo: ApiTokenRepo = Depends(ApiTokenRepo()), dns_server_repo: DnsServerRepo = Depends(DnsServerRepo()), http_server_repo: HttpServerRepo = Depends(HttpServerRepo()), token: TokenPayload = Depends(ScopedTo("api-token:create")), user: User = Depends(current_user), ): if form.dns_server_id and form.dns_server_id > 0: dns_server_name = (dns_server_repo.first_or_fail( id=form.dns_server_id).results().name) if form.http_server_id and form.http_server_id > 0: http_server_name = (http_server_repo.first_or_fail( id=form.http_server_id).results().name) scopes = [] for requested_scope in form.scopes.split(" "): request_scope_satisfied = False for user_token in token.scopes: # TODO: double check this, pretty lenient # if a:b in a:b:c if user_token in requested_scope: request_scope_satisfied = True if not request_scope_satisfied: logger.warning( f"[email protected]: Attempt to create unauthorized scope {requested_scope}" ) raise HTTPException(403, detail="unauthorized") else: scopes.append(requested_scope) # TODO: use better randomness token = create_bearer_token( data={ "sub": user.id, "scopes": " ".join(scopes), "dns_server_name": dns_server_name, "http_server_name": http_server_name, }) data = { "scopes": " ".join(scopes), "token": str(token), "expires_at": form.expires_at, "dns_server_id": form.dns_server_id, "http_server_id": form.http_server_id, } api_token = api_token_repo.create(data).data() return ApiTokenResponse(api_token=api_token)
async def index( sort_qs: SortQS = Depends(SortQS), pagination: PaginationQS = Depends(PaginationQS), zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("zone:list")), includes: List[str] = Query(None), ): # TODO: bypasses a bunch of scopes, find a way to restrict access via scopes includes = only(includes, ["dns_server", "dns_records", "http_server"], values=True) pg, items = (zone_repo.loads(includes).strict().sort(sort_qs).paginate( pagination).includes(includes).data()) return ZonesResponse(pagination=pg, zones=items)
async def sensitive( api_token_id: int, api_token_repo: ApiTokenRepo = Depends(ApiTokenRepo()), token: TokenPayload = Depends(ScopedTo("api-token:read")), includes: List[str] = Query(None), ): includes = only(includes, ["dns_server", "http_server"], values=True) # TODO: require stronger scope if not api_token_repo.exists(api_token_id): raise HTTPException(404, detail="Not found") api_token = (api_token_repo.loads(includes).set_data_model( SensitiveApiTokenData).includes(includes).data()) return SensitiveApiTokenResponse(api_token=api_token)
async def index( zone_id: int, sort_qs: SortQS = Depends(SortQS), pagination: PaginationQS = Depends(PaginationQS), dns_record_repo: DnsRecordRepo = Depends(DnsRecordRepo()), zone_repo: ZoneRepo = Depends(ZoneRepo()), token: TokenPayload = Depends(ScopedTo("dns-record:list")), includes: List[str] = Query(None), ): zone_repo.exists(id=zone_id, or_fail=True) includes = only(includes, ["zone"], values=True) pg, items = (dns_record_repo.loads("zone").sort(sort_qs).filter_by( zone_id=zone_id).paginate(pagination).includes(includes).data()) return DnsRecordsResponse(pagination=pg, dns_records=items)