mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 21:44:16 +02:00
[core] improvement: new configuration property to disable SSL checking when downloading files
This commit is contained in:
@@ -22,6 +22,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- publisher limit: 12%
|
- publisher limit: 12%
|
||||||
- version: the limit for displaying both the installed and latest versions is 22% (otherwise just the latest version will be displayed)
|
- version: the limit for displaying both the installed and latest versions is 22% (otherwise just the latest version will be displayed)
|
||||||
|
|
||||||
|
- Settings
|
||||||
|
- new property to disable SSL checking when downloading files (disabled by default)
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.10.3/check_ssl.png">
|
||||||
|
</p>
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Arch
|
- Arch
|
||||||
- conflict resolution: removing hard dependencies that would be satisfied with the inclusion of the new package [#268](https://github.com/vinifmor/bauh/issues/268)
|
- conflict resolution: removing hard dependencies that would be satisfied with the inclusion of the new package [#268](https://github.com/vinifmor/bauh/issues/268)
|
||||||
|
|||||||
@@ -407,6 +407,7 @@ download:
|
|||||||
icons: true # allows bauh to download the applications icons when they are not saved on the disk
|
icons: true # allows bauh to download the applications icons when they are not saved on the disk
|
||||||
multithreaded: true # allows bauh to use a multithreaded download client installed on the system to download applications source files faster
|
multithreaded: true # allows bauh to use a multithreaded download client installed on the system to download applications source files faster
|
||||||
multithreaded_client: null # defines the multi-threaded download tool to be used. If null, the default installed tool will be used (priority: aria2 > axel). Possible tools/values: aria2, axel
|
multithreaded_client: null # defines the multi-threaded download tool to be used. If null, the default installed tool will be used (priority: aria2 > axel). Possible tools/values: aria2, axel
|
||||||
|
check_ssl: true # if the security certificate (SSL) should be checked before downloading files.
|
||||||
gems: null # defines the enabled applications types managed by bauh (a null value means "all available")
|
gems: null # defines the enabled applications types managed by bauh (a null value means "all available")
|
||||||
locale: null # defines a different translation for bauh (a null value will retrieve the system's default locale)
|
locale: null # defines a different translation for bauh (a null value will retrieve the system's default locale)
|
||||||
store_root_password: true # if the root password should be asked only once
|
store_root_password: true # if the root password should be asked only once
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ def main():
|
|||||||
|
|
||||||
cache_factory = DefaultMemoryCacheFactory(expiration_time=0)
|
cache_factory = DefaultMemoryCacheFactory(expiration_time=0)
|
||||||
|
|
||||||
|
downloader = AdaptableFileDownloader(logger=logger, multithread_enabled=app_config['download']['multithreaded'],
|
||||||
|
multithread_client=app_config['download']['multithreaded_client'],
|
||||||
|
i18n=i18n, http_client=http_client,
|
||||||
|
check_ssl=app_config['download']['check_ssl'])
|
||||||
|
|
||||||
context = ApplicationContext(i18n=i18n,
|
context = ApplicationContext(i18n=i18n,
|
||||||
http_client=http_client,
|
http_client=http_client,
|
||||||
download_icons=bool(app_config['download']['icons']),
|
download_icons=bool(app_config['download']['icons']),
|
||||||
@@ -43,8 +48,7 @@ def main():
|
|||||||
disk_loader_factory=DefaultDiskCacheLoaderFactory(logger),
|
disk_loader_factory=DefaultDiskCacheLoaderFactory(logger),
|
||||||
logger=logger,
|
logger=logger,
|
||||||
distro=util.get_distro(),
|
distro=util.get_distro(),
|
||||||
file_downloader=AdaptableFileDownloader(logger, bool(app_config['download']['multithreaded']),
|
file_downloader=downloader,
|
||||||
i18n, http_client, app_config['download']['multithreaded_client']),
|
|
||||||
app_name=__app_name__,
|
app_name=__app_name__,
|
||||||
app_version=__version__,
|
app_version=__version__,
|
||||||
internet_checker=InternetChecker(offline=False),
|
internet_checker=InternetChecker(offline=False),
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ def new_manage_panel(app_args: Namespace, app_config: dict, logger: logging.Logg
|
|||||||
|
|
||||||
http_client = HttpClient(logger)
|
http_client = HttpClient(logger)
|
||||||
|
|
||||||
|
downloader = AdaptableFileDownloader(logger=logger, multithread_enabled=app_config['download']['multithreaded'],
|
||||||
|
multithread_client=app_config['download']['multithreaded_client'],
|
||||||
|
i18n=i18n, http_client=http_client,
|
||||||
|
check_ssl=app_config['download']['check_ssl'])
|
||||||
|
|
||||||
context = ApplicationContext(i18n=i18n,
|
context = ApplicationContext(i18n=i18n,
|
||||||
http_client=http_client,
|
http_client=http_client,
|
||||||
download_icons=bool(app_config['download']['icons']),
|
download_icons=bool(app_config['download']['icons']),
|
||||||
@@ -39,8 +44,7 @@ def new_manage_panel(app_args: Namespace, app_config: dict, logger: logging.Logg
|
|||||||
disk_loader_factory=DefaultDiskCacheLoaderFactory(logger),
|
disk_loader_factory=DefaultDiskCacheLoaderFactory(logger),
|
||||||
logger=logger,
|
logger=logger,
|
||||||
distro=util.get_distro(),
|
distro=util.get_distro(),
|
||||||
file_downloader=AdaptableFileDownloader(logger, bool(app_config['download']['multithreaded']),
|
file_downloader=downloader,
|
||||||
i18n, http_client, app_config['download']['multithreaded_client']),
|
|
||||||
app_name=__app_name__,
|
app_name=__app_name__,
|
||||||
app_version=__version__,
|
app_version=__version__,
|
||||||
internet_checker=InternetChecker(offline=app_args.offline),
|
internet_checker=InternetChecker(offline=app_args.offline),
|
||||||
|
|||||||
@@ -51,7 +51,8 @@ class CoreConfigManager(YAMLConfigManager):
|
|||||||
'download': {
|
'download': {
|
||||||
'multithreaded': False,
|
'multithreaded': False,
|
||||||
'multithreaded_client': None,
|
'multithreaded_client': None,
|
||||||
'icons': True
|
'icons': True,
|
||||||
|
'check_ssl': True
|
||||||
},
|
},
|
||||||
'store_root_password': True,
|
'store_root_password': True,
|
||||||
'disk': {
|
'disk': {
|
||||||
|
|||||||
@@ -23,13 +23,15 @@ RE_HAS_EXTENSION = re.compile(r'.+\.\w+$')
|
|||||||
|
|
||||||
class AdaptableFileDownloader(FileDownloader):
|
class AdaptableFileDownloader(FileDownloader):
|
||||||
|
|
||||||
def __init__(self, logger: logging.Logger, multithread_enabled: bool, i18n: I18n, http_client: HttpClient, multithread_client: str):
|
def __init__(self, logger: logging.Logger, multithread_enabled: bool, i18n: I18n, http_client: HttpClient,
|
||||||
|
multithread_client: str, check_ssl: bool):
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
self.multithread_enabled = multithread_enabled
|
self.multithread_enabled = multithread_enabled
|
||||||
self.i18n = i18n
|
self.i18n = i18n
|
||||||
self.http_client = http_client
|
self.http_client = http_client
|
||||||
self.supported_multithread_clients = ['aria2', 'axel']
|
self.supported_multithread_clients = ['aria2', 'axel']
|
||||||
self.multithread_client = multithread_client
|
self.multithread_client = multithread_client
|
||||||
|
self.check_ssl = check_ssl
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_aria2c_available() -> bool:
|
def is_aria2c_available() -> bool:
|
||||||
@@ -75,6 +77,9 @@ class AdaptableFileDownloader(FileDownloader):
|
|||||||
def _get_axel_process(self, url: str, output_path: str, cwd: str, root_password: Optional[str], threads: int) -> SimpleProcess:
|
def _get_axel_process(self, url: str, output_path: str, cwd: str, root_password: Optional[str], threads: int) -> SimpleProcess:
|
||||||
cmd = ['axel', url, '-n', str(threads), '-4', '-c', '-T', '5']
|
cmd = ['axel', url, '-n', str(threads), '-4', '-c', '-T', '5']
|
||||||
|
|
||||||
|
if not self.check_ssl:
|
||||||
|
cmd.append('-k')
|
||||||
|
|
||||||
if output_path:
|
if output_path:
|
||||||
cmd.append(f'--output={output_path}')
|
cmd.append(f'--output={output_path}')
|
||||||
|
|
||||||
@@ -83,6 +88,9 @@ class AdaptableFileDownloader(FileDownloader):
|
|||||||
def _get_wget_process(self, url: str, output_path: str, cwd: str, root_password: Optional[str]) -> SimpleProcess:
|
def _get_wget_process(self, url: str, output_path: str, cwd: str, root_password: Optional[str]) -> SimpleProcess:
|
||||||
cmd = ['wget', url, '-c', '--retry-connrefused', '-t', '10', '--no-config', '-nc']
|
cmd = ['wget', url, '-c', '--retry-connrefused', '-t', '10', '--no-config', '-nc']
|
||||||
|
|
||||||
|
if not self.check_ssl:
|
||||||
|
cmd.append('--no-check-certificate')
|
||||||
|
|
||||||
if output_path:
|
if output_path:
|
||||||
cmd.append('-O')
|
cmd.append('-O')
|
||||||
cmd.append(output_path)
|
cmd.append(output_path)
|
||||||
|
|||||||
@@ -128,6 +128,11 @@ class GenericSettingsManager(SettingsController):
|
|||||||
value=core_config['system']['single_dependency_checking'],
|
value=core_config['system']['single_dependency_checking'],
|
||||||
id_='dep_check')
|
id_='dep_check')
|
||||||
|
|
||||||
|
select_check_ssl = self._gen_bool_component(label=self.i18n['core.config.download.check_ssl'],
|
||||||
|
tooltip=self.i18n['core.config.download.check_ssl.tip'],
|
||||||
|
value=core_config['download']['check_ssl'],
|
||||||
|
id_='download.check_ssl')
|
||||||
|
|
||||||
select_dmthread = self._gen_bool_component(label=self.i18n['core.config.download.multithreaded'],
|
select_dmthread = self._gen_bool_component(label=self.i18n['core.config.download.multithreaded'],
|
||||||
tooltip=self.i18n['core.config.download.multithreaded.tip'],
|
tooltip=self.i18n['core.config.download.multithreaded.tip'],
|
||||||
id_="down_mthread",
|
id_="down_mthread",
|
||||||
@@ -135,7 +140,8 @@ class GenericSettingsManager(SettingsController):
|
|||||||
|
|
||||||
select_mthread_client = self._gen_multithread_client_select(core_config)
|
select_mthread_client = self._gen_multithread_client_select(core_config)
|
||||||
|
|
||||||
inputs = [select_dmthread, select_mthread_client, select_trim, select_dep_check, input_data_exp, input_icon_exp]
|
inputs = [select_dmthread, select_mthread_client, select_check_ssl, select_trim, select_dep_check,
|
||||||
|
input_data_exp, input_icon_exp]
|
||||||
panel = PanelComponent([FormComponent(inputs, spaces=False)], id_='advanced')
|
panel = PanelComponent([FormComponent(inputs, spaces=False)], id_='advanced')
|
||||||
return TabComponent(self.i18n['core.config.tab.advanced'].capitalize(), panel, None, 'core.adv')
|
return TabComponent(self.i18n['core.config.tab.advanced'].capitalize(), panel, None, 'core.adv')
|
||||||
|
|
||||||
@@ -380,9 +386,13 @@ class GenericSettingsManager(SettingsController):
|
|||||||
mthread_client = adv_form.get_component('mthread_client', SingleSelectComponent).get_selected()
|
mthread_client = adv_form.get_component('mthread_client', SingleSelectComponent).get_selected()
|
||||||
core_config['download']['multithreaded_client'] = mthread_client
|
core_config['download']['multithreaded_client'] = mthread_client
|
||||||
|
|
||||||
|
check_ssl = adv_form.get_component('download.check_ssl', SingleSelectComponent).get_selected()
|
||||||
|
core_config['download']['check_ssl'] = check_ssl
|
||||||
|
|
||||||
if isinstance(self.file_downloader, AdaptableFileDownloader):
|
if isinstance(self.file_downloader, AdaptableFileDownloader):
|
||||||
self.file_downloader.multithread_client = mthread_client
|
self.file_downloader.multithread_client = mthread_client
|
||||||
self.file_downloader.multithread_enabled = download_mthreaded
|
self.file_downloader.multithread_enabled = download_mthreaded
|
||||||
|
self.file_downloader.check_ssl = check_ssl
|
||||||
|
|
||||||
single_dep_check = adv_form.get_component('dep_check', SingleSelectComponent).get_selected()
|
single_dep_check = adv_form.get_component('dep_check', SingleSelectComponent).get_selected()
|
||||||
core_config['system']['single_dependency_checking'] = single_dep_check
|
core_config['system']['single_dependency_checking'] = single_dep_check
|
||||||
|
|||||||
@@ -221,6 +221,8 @@ core.config.backup.uninstall=Before uninstalling
|
|||||||
core.config.backup.upgrade=Before upgrading
|
core.config.backup.upgrade=Before upgrading
|
||||||
core.config.boot.load_apps=Load apps after startup
|
core.config.boot.load_apps=Load apps after startup
|
||||||
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
||||||
|
core.config.download.check_ssl=Check security certificate
|
||||||
|
core.config.download.check_ssl.tip=If the security certificate (SSL) should be checked before downloading files
|
||||||
core.config.download.icons=Download icons
|
core.config.download.icons=Download icons
|
||||||
core.config.download.icons.tip=If the application icons should be downloaded and displayed on the table
|
core.config.download.icons.tip=If the application icons should be downloaded and displayed on the table
|
||||||
core.config.download.multithreaded=Multithreaded download
|
core.config.download.multithreaded=Multithreaded download
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ core.config.backup.uninstall=Before uninstalling
|
|||||||
core.config.backup.upgrade=Before upgrading
|
core.config.backup.upgrade=Before upgrading
|
||||||
core.config.boot.load_apps=Load apps after startup
|
core.config.boot.load_apps=Load apps after startup
|
||||||
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
||||||
|
core.config.download.check_ssl=Check security certificate
|
||||||
|
core.config.download.check_ssl.tip=If the security certificate (SSL) should be checked before downloading files
|
||||||
core.config.download.icons=Download Icons
|
core.config.download.icons=Download Icons
|
||||||
core.config.download.icons.tip=Falls aktiviert werden die Anwendungs-Icons in der Tabelle angezeigt
|
core.config.download.icons.tip=Falls aktiviert werden die Anwendungs-Icons in der Tabelle angezeigt
|
||||||
core.config.download.multithreaded=Paralleler Download
|
core.config.download.multithreaded=Paralleler Download
|
||||||
|
|||||||
@@ -222,6 +222,8 @@ core.config.backup.upgrade=Before upgrading
|
|||||||
core.config.backup=Enabled
|
core.config.backup=Enabled
|
||||||
core.config.boot.load_apps=Load apps after startup
|
core.config.boot.load_apps=Load apps after startup
|
||||||
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
||||||
|
core.config.download.check_ssl=Check security certificate
|
||||||
|
core.config.download.check_ssl.tip=If the security certificate (SSL) should be checked before downloading files
|
||||||
core.config.download.icons.tip=If the application icons should be downloaded and displayed on the table
|
core.config.download.icons.tip=If the application icons should be downloaded and displayed on the table
|
||||||
core.config.download.icons=Download icons
|
core.config.download.icons=Download icons
|
||||||
core.config.download.multithreaded=Multi-threaded download
|
core.config.download.multithreaded=Multi-threaded download
|
||||||
|
|||||||
@@ -221,6 +221,8 @@ core.config.backup.uninstall=Antes de desinstalar
|
|||||||
core.config.backup.upgrade=Antes de actualizar
|
core.config.backup.upgrade=Antes de actualizar
|
||||||
core.config.boot.load_apps=Cargar aplicaciones al inicio
|
core.config.boot.load_apps=Cargar aplicaciones al inicio
|
||||||
core.config.boot.load_apps.tip= Si las aplicaciones instaladas o sugerencias deben ser cargadas en el panel de administración después del proceso de inicialización
|
core.config.boot.load_apps.tip= Si las aplicaciones instaladas o sugerencias deben ser cargadas en el panel de administración después del proceso de inicialización
|
||||||
|
core.config.download.check_ssl=Comprobar certificado de seguridad
|
||||||
|
core.config.download.check_ssl.tip=Si se debe verificar el certificado de seguridad (SSL) antes de descargar archivos
|
||||||
core.config.download.icons=Descargar iconos
|
core.config.download.icons=Descargar iconos
|
||||||
core.config.download.icons.tip=Si los íconos de las aplicaciones se deben descargar y mostrar en la tabla
|
core.config.download.icons.tip=Si los íconos de las aplicaciones se deben descargar y mostrar en la tabla
|
||||||
core.config.download.multithreaded=Descarga segmentada
|
core.config.download.multithreaded=Descarga segmentada
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ core.config.backup.upgrade=Avant de mettre à jour
|
|||||||
core.config.backup=Activé
|
core.config.backup=Activé
|
||||||
core.config.boot.load_apps=Load apps after startup
|
core.config.boot.load_apps=Load apps after startup
|
||||||
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
||||||
|
core.config.download.check_ssl=Check security certificate
|
||||||
|
core.config.download.check_ssl.tip=If the security certificate (SSL) should be checked before downloading files
|
||||||
core.config.download.icons.tip=Si les icônes de l'application devraient être téléchargées et affichées sur le tableau
|
core.config.download.icons.tip=Si les icônes de l'application devraient être téléchargées et affichées sur le tableau
|
||||||
core.config.download.icons=Télécharger les icônes
|
core.config.download.icons=Télécharger les icônes
|
||||||
core.config.download.multithreaded=Téléchargement parallèles
|
core.config.download.multithreaded=Téléchargement parallèles
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ core.config.backup.uninstall=Before uninstalling
|
|||||||
core.config.backup.upgrade=Before upgrading
|
core.config.backup.upgrade=Before upgrading
|
||||||
core.config.boot.load_apps=Load apps after startup
|
core.config.boot.load_apps=Load apps after startup
|
||||||
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
||||||
|
core.config.download.check_ssl=Check security certificate
|
||||||
|
core.config.download.check_ssl.tip=If the security certificate (SSL) should be checked before downloading files
|
||||||
core.config.download.icons=Download icons
|
core.config.download.icons=Download icons
|
||||||
core.config.download.icons.tip=If the application icons should be downloaded and displayed on the table
|
core.config.download.icons.tip=If the application icons should be downloaded and displayed on the table
|
||||||
core.config.download.multithreaded=Multithreaded download
|
core.config.download.multithreaded=Multithreaded download
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ core.config.backup.upgrade=Antes de atualizar
|
|||||||
core.config.backup=Habilitada
|
core.config.backup=Habilitada
|
||||||
core.config.boot.load_apps=Carregar aplicativos após iniciar
|
core.config.boot.load_apps=Carregar aplicativos após iniciar
|
||||||
core.config.boot.load_apps.tip=Se os aplicativos instalados ou sugestões devem ser carregados no painel de gerenciamento após a inicialização.
|
core.config.boot.load_apps.tip=Se os aplicativos instalados ou sugestões devem ser carregados no painel de gerenciamento após a inicialização.
|
||||||
|
core.config.download.check_ssl=Verificar certificado de segurança
|
||||||
|
core.config.download.check_ssl.tip=Se o certificado de segurança (SSL) deve ser verificado antes de baixar arquivos
|
||||||
core.config.download.icons.tip=Se os ícones dos aplicativos devem ser baixados e exibidos na tabela
|
core.config.download.icons.tip=Se os ícones dos aplicativos devem ser baixados e exibidos na tabela
|
||||||
core.config.download.icons=Baixar ícones
|
core.config.download.icons=Baixar ícones
|
||||||
core.config.download.multithreaded.tip=Se os aplicativos, pacotes e arquivos devem ser baixados através de uma ferramenta que trabalha com segmentação / threads (pode ser mais rápido).
|
core.config.download.multithreaded.tip=Se os aplicativos, pacotes e arquivos devem ser baixados através de uma ferramenta que trabalha com segmentação / threads (pode ser mais rápido).
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ core.config.backup.uninstall=Before uninstalling
|
|||||||
core.config.backup.upgrade=Before upgrading
|
core.config.backup.upgrade=Before upgrading
|
||||||
core.config.boot.load_apps=Load apps after startup
|
core.config.boot.load_apps=Load apps after startup
|
||||||
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
||||||
|
core.config.download.check_ssl=Check security certificate
|
||||||
|
core.config.download.check_ssl.tip=If the security certificate (SSL) should be checked before downloading files
|
||||||
core.config.download.icons=Скачать иконки
|
core.config.download.icons=Скачать иконки
|
||||||
core.config.download.icons.tip=Загружать иконки приложения для отображаения на рабочем столе
|
core.config.download.icons.tip=Загружать иконки приложения для отображаения на рабочем столе
|
||||||
core.config.download.multithreaded=Многопоточная загрузка
|
core.config.download.multithreaded=Многопоточная загрузка
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ core.config.backup.upgrade=Önce yükseltiliyor
|
|||||||
core.config.backup=Etkin
|
core.config.backup=Etkin
|
||||||
core.config.boot.load_apps=Load apps after startup
|
core.config.boot.load_apps=Load apps after startup
|
||||||
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
core.config.boot.load_apps.tip=If the installed applications or suggestions should be loaded on the management panel after the initialization process
|
||||||
|
core.config.download.check_ssl=Check security certificate
|
||||||
|
core.config.download.check_ssl.tip=If the security certificate (SSL) should be checked before downloading files
|
||||||
core.config.download.icons.tip=Tabloda görüntüleniyorsa uygulama simgeleri indirilmeli
|
core.config.download.icons.tip=Tabloda görüntüleniyorsa uygulama simgeleri indirilmeli
|
||||||
core.config.download.icons=Simgeleri indir
|
core.config.download.icons=Simgeleri indir
|
||||||
core.config.download.multithreaded.tip=Uygulamaların, paketlerin ve dosyaların iş parçacıklarıyla (daha hızlı) çalışan bir araçla indirilip indirilmeyeceği.
|
core.config.download.multithreaded.tip=Uygulamaların, paketlerin ve dosyaların iş parçacıklarıyla (daha hızlı) çalışan bir araçla indirilip indirilmeyeceği.
|
||||||
|
|||||||
Reference in New Issue
Block a user