def hosting_post_save_handler(sender, instance, created, using, **kwargs): syncano_instance_pk = get_current_instance().pk new_cname = Hosting.find_cname(instance.domains) if created: old_cname = None else: old_cname = Hosting.find_cname(instance.old_value('domains')) if new_cname != old_cname: with transaction.atomic(): syncano_instance = Instance.objects.select_for_update().get(pk=syncano_instance_pk) if new_cname is not None: add_domains_to_syncano_instance(syncano_instance, domains=[new_cname]) if old_cname is not None: remove_domains_from_syncano_instance(syncano_instance, domains=[old_cname]) syncano_instance.save(update_fields=['domains']) if instance.ssl_status == Hosting.SSL_STATUSES.CHECKING: add_post_transaction_success_operation( HostingAddSecureCustomDomainTask.delay, using=using, hosting_pk=instance.id, domain=instance.get_cname(), instance_pk=syncano_instance_pk, )
def test_if_file_is_deleted_on_instance_deletion(self): self._post_file('some special delete content', path='pages/delete.html') hosting_file = HostingFile.objects.first() self.assertTrue(Hosting.get_storage().exists(hosting_file.file_object.name)) self.instance.delete() self.assertFalse(Hosting.get_storage().exists(hosting_file.file_object.name))
def to_instance(self, storage, representation): file_object = storage.get_file(representation['file_object']) storage.update_storage_size(file_object.size) new_path = upload_hosting_file_to(Munch(representation), os.path.basename(file_object.name)) Hosting.get_storage().save(new_path, file_object) representation['file_object'] = new_path return super().to_instance(storage, representation)
def test_if_file_is_deleted(self): self._post_file('some special delete content', path='pages/delete.html') hosting_file = HostingFile.objects.first() self.assertTrue(Hosting.get_storage().exists(hosting_file.file_object.name)) url = reverse('v1.1:hosting-file-detail', args=(self.instance.name, self.hosting.id, hosting_file.id)) self.client.delete(url) self.assertFalse(Hosting.get_storage().exists(hosting_file.file_object.name)) usage = InstanceIndicator.objects.get(instance=self.instance, type=InstanceIndicator.TYPES.STORAGE_SIZE).value self.assertEqual(usage, 0)
def backup_object(self, storage, obj): # Remove CNAME and set ssl status to off on backup obj['ssl_status'] = Hosting.SSL_STATUSES.OFF cname = Hosting.find_cname(obj['domains']) if cname: obj['domains'].remove(cname) super().backup_object(storage, obj)
def test_file_update(self): create_response = self._post_file('<html><body>Hi!</body></html>') self.assertEqual(create_response.status_code, status.HTTP_201_CREATED) created_hosting_file = HostingFile.objects.get( id=create_response.data['id']) file_content = '<html><body>Hi Test!</body></html>' tmp_file = SimpleUploadedFile('index.html', file_content.encode(), content_type='text/html') response = self.client.put(reverse('v1.1:hosting-file-detail', args=(self.instance.name, self.hosting.id, create_response.data['id'])), data={ 'file': tmp_file, 'path': 'page/[email protected]' }, format='multipart') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['size'], len(file_content)) self.assertEqual(create_response.data['path'], response.data['path']) self.assertNotEqual(create_response.data['checksum'], response.data['checksum']) # check if old file is deleted; self.assertFalse(Hosting.get_storage().exists( created_hosting_file.file_object.name))
def test_socket_mapping_hosting_with_auth(self): self.socket = G(Socket, name='test', status=Socket.STATUSES.OK) self.script = G(CodeBox, socket=self.socket, path='fake_path') self.endpoint = G(SocketEndpoint, socket=self.socket, name='test/test', calls=[{ 'type': 'script', 'path': 'fake_path', 'methods': ['*'] }]) self.hosting.auth = {'user1': Hosting.encrypt_passwd('passwd1')} self.hosting.config = {'sockets_mapping': [["/", "test/test"]]} self.hosting.save() del self.client.defaults['HTTP_X_API_KEY'] with mock.patch('apps.webhooks.mixins.uwsgi') as uwsgi_mock: response = self.client.get(self.url) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) http_auth = 'Basic {}'.format( base64.b64encode(b'user1:passwd1').decode()) response = self.client.get(self.url, HTTP_AUTHORIZATION=http_auth) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertTrue(uwsgi_mock.add_var.called)
def test_authorization(self): self.hosting.auth = {'user1': Hosting.encrypt_passwd('passwd1')} self.hosting.save() response = self.client.get(self.url) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) http_auth = 'Basic {}'.format( base64.b64encode(b'user1:passwd1').decode()) response = self.client.get(self.url, HTTP_AUTHORIZATION=http_auth) self.assertEqual(response.status_code, status.HTTP_200_OK)
def handle_missing_file(self, request, hosting, query, path): # Return default web pages if path is empty and hosting has no files. if hosting.is_empty and path == self.DEFAULT_FILE: return HttpResponse(self.DEFAULT_CONTENT_TMPL.substitute( iframe=self.EMPTY_INDEX_IFRAME), content_type='text/html') # Return index.html if browser router is enabled. if hosting.is_browser_router_enabled: try: hosting_file = HostingFile.get_file(hosting=hosting, path=self.DEFAULT_FILE) except HostingFile.DoesNotExist: pass else: return self.get_accel_response( request, url=Hosting.get_storage().internal_url( hosting_file.file_object.name), url_404=self.EMPTY_404_KEY, query=query) # Check for custom 404. try: hosting_file = HostingFile.get_file(hosting=hosting, path=self.DEFAULT_404_FILE) except HostingFile.DoesNotExist: return self.create_404_response() url_404 = Hosting.get_storage().internal_url( hosting_file.file_object.name) return self.get_accel_response(request, url='{}/{}'.format( url_404.rsplit('/', 1)[0], path), url_404=url_404, query=query)
def process(self, request, *args, **kwargs): path = escape_uri_path(request.path) try: hosting = Cached(Hosting, kwargs=self.get_hosting_search_kwargs( domain=kwargs.get('domain'))).get() except Hosting.DoesNotExist: return self.create_404_response() if hosting.auth and not self.check_auth(request, hosting): # Either they did not provide an authorization header or # something in the authorization attempt failed. Send a 401 # back to them to ask them to authenticate. response = HttpResponse(status=status.HTTP_401_UNAUTHORIZED) response['WWW-Authenticate'] = 'Basic realm="Restricted"' return response for pattern, socket in hosting.config.get('sockets_mapping', []): if glob(pattern, path): request.version = 'v2' return run_api_view('socket-endpoint-endpoint', (request.instance.name, socket), request) if request.method != 'GET': self.http_method_not_allowed(request) # Strip '/' prefix for further processing. if path.endswith( '/' ): # jekyll like: '/about/' we should find path '/about/index.html' in such case; path = '{}{}'.format(path, self.DEFAULT_FILE) path = path.lstrip('/') query = iri_to_uri(request.META.get('QUERY_STRING', '')) try: hosting_file = HostingFile.get_file(hosting=hosting, path=path) return self.get_accel_response( request, Hosting.get_storage().internal_url( hosting_file.file_object.name), self.EMPTY_404_KEY, query) except HostingFile.DoesNotExist: return self.handle_missing_file(request, hosting, query, path)
def validate_auth(self, value): for uname, passwd in value.items(): if not passwd.startswith('crypt:'): value[uname] = Hosting.encrypt_passwd(passwd) return value
def backup_object(self, storage, obj): path = obj['file_object'] obj['file_object'] = storage.add_file(Hosting.get_storage().open(path)) super().backup_object(storage, obj)