diff --git a/retoors/services/lock_manager.py b/retoors/services/lock_manager.py new file mode 100644 index 0000000..6c7675c --- /dev/null +++ b/retoors/services/lock_manager.py @@ -0,0 +1,29 @@ +import asyncio +from collections import defaultdict +from typing import Dict + + +class LockManager: + + def __init__(self): + self._locks: Dict[str, asyncio.Lock] = {} + self._master_lock = asyncio.Lock() + + async def get_lock(self, identifier: str) -> asyncio.Lock: + async with self._master_lock: + if identifier not in self._locks: + self._locks[identifier] = asyncio.Lock() + return self._locks[identifier] + + async def cleanup_unused_locks(self): + async with self._master_lock: + to_remove = [key for key, lock in self._locks.items() if not lock.locked()] + for key in to_remove: + del self._locks[key] + + +_global_lock_manager = LockManager() + + +def get_lock_manager() -> LockManager: + return _global_lock_manager diff --git a/retoors/templates/components/cookie_banner.html b/retoors/templates/components/cookie_banner.html new file mode 100644 index 0000000..4c49648 --- /dev/null +++ b/retoors/templates/components/cookie_banner.html @@ -0,0 +1,228 @@ + + + + + + + diff --git a/retoors/templates/pages/aup.html b/retoors/templates/pages/aup.html new file mode 100644 index 0000000..e70715d --- /dev/null +++ b/retoors/templates/pages/aup.html @@ -0,0 +1,94 @@ +{% extends "layouts/base.html" %} +{% block title %}Acceptable Use Policy{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
+
+

Acceptable Use Policy

+

Last updated: January 2025

+

This Acceptable Use Policy governs your use of Retoor's Cloud Solutions services. By using our services, you agree to comply with this policy.

+ +

1. Prohibited Content

+

You may not use our services to store, share, or distribute content that:

+ + +

2. Prohibited Activities

+

You may not use our services to:

+ + +

3. Resource Usage Limits

+

Your use of our services is subject to the following limits:

+ +

Excessive resource usage that impacts service performance for other users may result in throttling or suspension.

+ +

4. Security Requirements

+

You are responsible for:

+ + +

5. Consequences of Violation

+

Violation of this Acceptable Use Policy may result in:

+ + +

6. Reporting Abuse

+

If you become aware of any violation of this policy, please report it to us immediately:

+ +

We will investigate all reports and take appropriate action within a reasonable timeframe.

+ +

7. Investigation Rights

+

We reserve the right to:

+ + +

8. Modifications to This Policy

+

We may modify this Acceptable Use Policy at any time. Continued use of our services after modifications constitutes acceptance of the updated policy.

+ +

9. Questions

+

If you have questions about this policy, please contact us at: legal@retoors.nl

+
+
+{% endblock %} diff --git a/retoors/templates/pages/compliance.html b/retoors/templates/pages/compliance.html new file mode 100644 index 0000000..5070d18 --- /dev/null +++ b/retoors/templates/pages/compliance.html @@ -0,0 +1,194 @@ +{% extends "layouts/base.html" %} +{% block title %}Security & Compliance{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
+
+

Security & Compliance

+

Retoor's Cloud Solutions is committed to maintaining the highest standards of security and compliance to protect your data and ensure regulatory adherence.

+ +

1. Data Security Measures

+ +

1.1 Encryption Standards

+ + + + + + + + + + + + + + + + + + + + + + + + + +
TypeStandardDescription
Data in TransitTLS 1.3All data transmitted between your device and our servers is encrypted using the latest TLS protocol
Data at RestAES-256All stored files are encrypted using industry-standard AES-256 encryption
DatabaseAES-256User credentials and metadata are encrypted at the database level
+ +

1.2 Access Control

+ + +

1.3 Infrastructure Security

+ + +

2. Compliance Certifications

+ +

2.1 GDPR Compliance

+

We are fully compliant with the General Data Protection Regulation (GDPR):

+ + +

2.2 ISO 27001

+

Our information security management system is aligned with ISO 27001 standards:

+ + +

2.3 SOC 2 Type II

+

We maintain SOC 2 Type II compliance covering:

+ + +

3. Data Center Locations

+

Your data is stored exclusively in European Union data centers:

+ + + + + + + + + + + + + + + + + + + + +
LocationProviderCertifications
Falkenstein, GermanyHetzner Online GmbHISO 27001, PCI DSS
Helsinki, FinlandHetzner Online GmbHISO 27001, PCI DSS
+

All data centers feature:

+ + +

4. Data Processing Agreement

+

For business customers, we provide a comprehensive Data Processing Agreement (DPA) that includes:

+ +

Download DPA Template

+ +

5. Security Monitoring

+

We continuously monitor our systems for security threats:

+ + +

6. Incident Response

+

In the event of a security incident:

+ + +

7. Employee Security

+

All employees undergo rigorous security protocols:

+ + +

8. Third-Party Audits

+

We undergo regular third-party security audits:

+ + +

9. Security Best Practices for Users

+

We recommend the following security practices:

+ + +

10. Questions and Reporting

+

For security-related inquiries or to report vulnerabilities:

+ +
+
+{% endblock %} diff --git a/retoors/templates/pages/cookies.html b/retoors/templates/pages/cookies.html new file mode 100644 index 0000000..dd16d4b --- /dev/null +++ b/retoors/templates/pages/cookies.html @@ -0,0 +1,80 @@ +{% extends "layouts/base.html" %} +{% block title %}Cookie Policy{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
+
+

Cookie Policy

+

Last updated: January 2025

+ +

1. What Are Cookies

+

Cookies are small text files that are placed on your device when you visit our website. They help us provide you with a better experience by remembering your preferences and understanding how you use our service.

+ +

2. Cookie Categories

+ +

2.1 Strictly Necessary Cookies

+

These cookies are essential for the website to function properly. They enable core functionality such as security, network management, and accessibility. You cannot opt out of these cookies as they are required for the service to work.

+ + + + + + + + + + + + + + + + + +
NameProviderPurposeDuration
sessionRetoor's Cloud SolutionsMaintains your login sessionSession
+ +

2.2 Functional Cookies

+

These cookies allow us to remember choices you make and provide enhanced, more personalized features.

+ +

2.3 Analytics Cookies

+

These cookies help us understand how visitors interact with our website by collecting and reporting information anonymously. We use this data to improve our service.

+ +

2.4 Marketing/Tracking Cookies

+

We currently do not use marketing or tracking cookies.

+ +

3. Third-Party Cookies

+

We may use third-party services that set cookies on our behalf. These services include:

+ + +

4. Legal Basis

+

We use strictly necessary cookies based on our legitimate interest in providing a functional service. For all other cookies, we obtain your explicit consent before placing them on your device.

+ +

5. How to Manage Cookies

+

You can control and manage cookies in several ways:

+ + +

Browser-Specific Instructions

+ + +

6. Changes to This Policy

+

We may update this Cookie Policy from time to time. Any changes will be posted on this page with an updated revision date.

+ +

7. Contact Us

+

If you have any questions about our use of cookies, please contact us through our support page.

+
+
+{% endblock %} diff --git a/retoors/templates/pages/file_editor.html b/retoors/templates/pages/file_editor.html new file mode 100644 index 0000000..4ce7cf7 --- /dev/null +++ b/retoors/templates/pages/file_editor.html @@ -0,0 +1,159 @@ +{% extends "layouts/dashboard.html" %} + +{% block title %}{{ file_path.split('/')[-1] }} - Editor - Retoor's Cloud Solutions{% endblock %} + +{% block dashboard_head %} + + +{% endblock %} + +{% block page_title %}Editing: {{ file_path }}{% endblock %} + +{% block dashboard_actions %} + Back to Files +{% endblock %} + +{% block dashboard_content %} +
+
+
+ {{ file_path }} +
+
+ + +
+
+ +
+ + + + + + + + + + + + + +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/impressum.html b/retoors/templates/pages/impressum.html new file mode 100644 index 0000000..5c0faff --- /dev/null +++ b/retoors/templates/pages/impressum.html @@ -0,0 +1,67 @@ +{% extends "layouts/base.html" %} +{% block title %}Impressum{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
+
+

Impressum

+

Information in accordance with Dutch law requirements

+ +

Company Information

+ + + + + + + + + + + + + + + + + + + +
Company Name:Retoor's Cloud Solutions
Legal Form:Sole Proprietorship
KvK Number:[To be filled in]
BTW/VAT Number:[To be filled in]
+ +

Contact Information

+ + + + + + + + + + + + + + + +
Business Address:[Street Address]
[Postal Code] [City]
The Netherlands
Email:contact@retoors.nl
Phone:[Phone Number]
+ +

Dispute Resolution

+

The European Commission provides a platform for online dispute resolution (ODR): https://ec.europa.eu/consumers/odr

+

We are not willing or obliged to participate in dispute resolution proceedings before a consumer arbitration board.

+ +

Liability for Content

+

As service providers, we are liable for own contents of these websites according to general laws. However, we are not obliged to monitor external information provided or stored on our website. Once we have become aware of a specific infringement of the law, we will immediately remove the content in question.

+ +

Liability for Links

+

Our website contains links to external websites, over whose contents we have no control. Therefore, we cannot accept any liability for these external contents. The respective provider or operator of the websites is always responsible for the contents of the linked websites.

+ +

Copyright

+

The contents and works on these pages created by the site operators are subject to Dutch copyright law. The duplication, processing, distribution and any kind of utilization outside the limits of copyright law require the written consent of the respective author or creator.

+
+
+{% endblock %} diff --git a/retoors/templates/pages/media_viewer.html b/retoors/templates/pages/media_viewer.html new file mode 100644 index 0000000..62c78ca --- /dev/null +++ b/retoors/templates/pages/media_viewer.html @@ -0,0 +1,135 @@ +{% extends "layouts/dashboard.html" %} + +{% block title %}{{ file_path.split('/')[-1] }} - Viewer - Retoor's Cloud Solutions{% endblock %} + +{% block dashboard_head %} + +{% endblock %} + +{% block page_title %}Viewing: {{ file_path }}{% endblock %} + +{% block dashboard_actions %} + Back to Files +{% endblock %} + +{% block dashboard_content %} +
+
+
+ {{ file_path }} +
+
+ +
+
+
+

Loading...

+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/retoors/templates/pages/sla.html b/retoors/templates/pages/sla.html new file mode 100644 index 0000000..99797de --- /dev/null +++ b/retoors/templates/pages/sla.html @@ -0,0 +1,219 @@ +{% extends "layouts/base.html" %} +{% block title %}Service Level Agreement{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
+
+

Service Level Agreement

+

Last updated: January 2025

+

This Service Level Agreement applies to Business and Enterprise plan customers of Retoor's Cloud Solutions.

+ +

1. Service Availability

+ +

1.1 Uptime Guarantee

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Service TierMonthly Uptime GuaranteeMaximum Downtime per Month
Personal99.0%7.2 hours
Professional99.5%3.6 hours
Business99.9%43.2 minutes
Enterprise99.95%21.6 minutes
+ +

1.2 Planned Maintenance

+

Planned maintenance windows do not count against uptime guarantees. We will:

+ + +

2. Support Response Times

+ +

2.1 Support Channels

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Service TierSupport ChannelsSupport Hours
PersonalEmail onlyBusiness hours (9-17 CET)
ProfessionalEmail, ChatExtended hours (8-20 CET)
BusinessEmail, Chat, Phone24/7
EnterpriseEmail, Chat, Phone, Dedicated Account Manager24/7
+ +

2.2 Response Time Commitments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Priority LevelDescriptionBusiness PlanEnterprise Plan
Critical (P1)Service completely unavailable1 hour30 minutes
High (P2)Major functionality impaired4 hours2 hours
Medium (P3)Minor functionality issues1 business day8 hours
Low (P4)General questions, feature requests2 business days1 business day
+ +

3. Data Backup Guarantees

+ + +

4. Performance Standards

+ + +

5. Service Credits

+ +

5.1 Credit Calculation

+

If we fail to meet the uptime guarantee, you are eligible for service credits:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
Monthly Uptime PercentageService Credit
99.0% - 99.5%10% of monthly fee
95.0% - 99.0%25% of monthly fee
90.0% - 95.0%50% of monthly fee
Below 90.0%100% of monthly fee
+ +

5.2 Claiming Credits

+

To claim service credits:

+ + +

6. Exclusions

+

This SLA does not apply to service unavailability caused by:

+ + +

7. Monitoring and Reporting

+

We provide:

+ + +

8. Changes to This SLA

+

We may modify this SLA with 30 days notice. Material changes that reduce service levels will allow you to terminate your contract without penalty.

+ +

9. Contact

+

For SLA-related questions or to report service issues:

+ +
+
+{% endblock %} diff --git a/retoors/templates/pages/user_rights.html b/retoors/templates/pages/user_rights.html new file mode 100644 index 0000000..b59aba8 --- /dev/null +++ b/retoors/templates/pages/user_rights.html @@ -0,0 +1,88 @@ +{% extends "layouts/base.html" %} +{% block title %}User Rights Request{% endblock %} +{% block head %} + {{ super() }} + +{% endblock %} +{% block content %} +
+
+

User Rights Request

+

Under the General Data Protection Regulation (GDPR), you have several rights regarding your personal data. You can exercise these rights by submitting a request below.

+ +

Your Rights Under GDPR

+ + +

Request Data Access

+

Request a download of all your personal data that we store.

+
+
+ + +
+
+ + +
+ +
+ +

Request Data Deletion

+

Request the permanent deletion of your account and all associated data.

+
+
+ + +
+
+ + +
+
+ +
+ +
+ +

Request Data Correction

+

Request correction of inaccurate or incomplete personal data.

+
+
+ + +
+
+ + +
+ +
+ +

Response Time

+

We will respond to your request within 30 days of receipt. If we need additional time, we will notify you and provide a reason for the delay.

+ +

Contact for Privacy Concerns

+

If you have any questions about your rights or how we process your data, please contact us at: privacy@retoors.nl

+ +

File a Complaint

+

If you believe your data protection rights have been violated, you have the right to lodge a complaint with the Dutch Data Protection Authority (Autoriteit Persoonsgegevens):

+

+ Autoriteit Persoonsgegevens
+ Postbus 93374
+ 2509 AJ Den Haag
+ The Netherlands
+ Website: https://autoriteitpersoonsgegevens.nl +

+
+
+{% endblock %} diff --git a/retoors/views/editor.py b/retoors/views/editor.py new file mode 100644 index 0000000..6ef0271 --- /dev/null +++ b/retoors/views/editor.py @@ -0,0 +1,84 @@ +from aiohttp import web +import aiohttp_jinja2 +from aiohttp.web_response import json_response + +from ..helpers.auth import login_required + + +class FileEditorView(web.View): + @login_required + async def get(self): + file_path = self.request.query.get('path', '') + user = self.request.get('user') + + if not file_path: + return web.Response(text="No file path specified", status=400) + + return aiohttp_jinja2.render_template( + 'pages/file_editor.html', + self.request, + { + 'request': self.request, + 'user': user, + 'file_path': file_path, + 'active_page': 'files' + } + ) + + @login_required + async def post(self): + user_email = self.request['user']['email'] + file_service = self.request.app['file_service'] + + try: + data = await self.request.json() + file_path = data.get('path') + content = data.get('content') + + if not file_path: + return json_response({'status': 'error', 'message': 'No file path specified'}, status=400) + + if content is None: + return json_response({'status': 'error', 'message': 'No content provided'}, status=400) + + success = await file_service.save_file_content(user_email, file_path, content) + + if success: + return json_response({'status': 'success', 'message': 'File saved successfully'}) + else: + return json_response({'status': 'error', 'message': 'Failed to save file'}, status=500) + + except Exception as e: + return json_response({'status': 'error', 'message': str(e)}, status=500) + + +class FileContentView(web.View): + @login_required + async def get(self): + user_email = self.request['user']['email'] + file_service = self.request.app['file_service'] + file_path = self.request.query.get('path', '') + binary = self.request.query.get('binary', 'false').lower() == 'true' + + if not file_path: + return json_response({'status': 'error', 'message': 'No file path specified'}, status=400) + + try: + if binary: + content_bytes = await file_service.read_file_content_binary(user_email, file_path) + if content_bytes is not None: + import base64 + content = base64.b64encode(content_bytes).decode('utf-8') + return json_response({'status': 'success', 'content': content}) + else: + return json_response({'status': 'error', 'message': 'File not found or cannot be read'}, status=404) + else: + content = await file_service.read_file_content(user_email, file_path) + + if content is not None: + return json_response({'status': 'success', 'content': content}) + else: + return json_response({'status': 'error', 'message': 'File not found or cannot be read'}, status=404) + + except Exception as e: + return json_response({'status': 'error', 'message': str(e)}, status=500) diff --git a/retoors/views/viewer.py b/retoors/views/viewer.py new file mode 100644 index 0000000..6c28da5 --- /dev/null +++ b/retoors/views/viewer.py @@ -0,0 +1,44 @@ +from aiohttp import web +import aiohttp_jinja2 +from pathlib import Path + +from ..helpers.auth import login_required + + +class ViewerView(web.View): + @login_required + async def get(self): + file_path = self.request.query.get('path', '') + user = self.request.get('user') + + if not file_path: + return web.Response(text="No file path specified", status=400) + + # Get file extension to determine media type + file_ext = Path(file_path).suffix.lower() + + # Determine media type + image_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'} + video_extensions = {'.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', '.mkv'} + audio_extensions = {'.mp3', '.wav', '.flac', '.aac', '.ogg', '.m4a'} + + if file_ext in image_extensions: + media_type = 'image' + elif file_ext in video_extensions: + media_type = 'video' + elif file_ext in audio_extensions: + media_type = 'audio' + else: + return web.Response(text="Unsupported file type for viewing", status=400) + + return aiohttp_jinja2.render_template( + 'pages/media_viewer.html', + self.request, + { + 'request': self.request, + 'user': user, + 'file_path': file_path, + 'media_type': media_type, + 'active_page': 'files' + } + ) \ No newline at end of file