mirror of
https://github.com/lnbits/lnbits.git
synced 2026-08-13 12:42:47 +02:00
needed for permssions to trigger from wasm extension json
This commit is contained in:
parent
03daf8b218
commit
3eb3126efd
3 changed files with 132 additions and 7 deletions
|
|
@ -47,6 +47,7 @@ class ExplicitRelease(BaseModel):
|
|||
details_link: str | None
|
||||
paid_features: str | None
|
||||
pay_link: str | None
|
||||
extension_type: str | None = None
|
||||
|
||||
def is_version_compatible(self):
|
||||
return is_lnbits_version_ok(self.min_lnbits_version, self.max_lnbits_version)
|
||||
|
|
@ -111,6 +112,12 @@ class ExtensionConfig(BaseModel):
|
|||
def is_version_compatible(self) -> bool:
|
||||
return is_lnbits_version_ok(self.min_lnbits_version, self.max_lnbits_version)
|
||||
|
||||
@classmethod
|
||||
async def fetch_release_config(cls, url: str) -> ExtensionConfig:
|
||||
error_msg = "Cannot fetch extension release config"
|
||||
config = await github_api_get(url, error_msg)
|
||||
return ExtensionConfig.parse_obj(config)
|
||||
|
||||
@classmethod
|
||||
async def fetch_github_release_config(
|
||||
cls, org: str, repo: str, tag_name: str
|
||||
|
|
@ -118,9 +125,7 @@ class ExtensionConfig(BaseModel):
|
|||
config_url = (
|
||||
f"https://raw.githubusercontent.com/{org}/{repo}/{tag_name}/config.json"
|
||||
)
|
||||
error_msg = "Cannot fetch GitHub extension config"
|
||||
config = await github_api_get(config_url, error_msg)
|
||||
return ExtensionConfig.parse_obj(config)
|
||||
return await cls.fetch_release_config(config_url)
|
||||
|
||||
|
||||
class ReleasePaymentInfo(BaseModel):
|
||||
|
|
@ -350,6 +355,8 @@ class ExtensionRelease(BaseModel):
|
|||
repo: str | None = None
|
||||
icon: str | None = None
|
||||
details_link: str | None = None
|
||||
extension_type: str | None = None
|
||||
permissions: list[ExtensionPermission] = []
|
||||
|
||||
paid_features: str | None = None
|
||||
pay_link: str | None = None
|
||||
|
|
@ -357,6 +364,14 @@ class ExtensionRelease(BaseModel):
|
|||
paid_sats: int | None = 0
|
||||
payment_hash: str | None = None
|
||||
|
||||
def apply_config(self, config: ExtensionConfig) -> None:
|
||||
self.min_lnbits_version = config.min_lnbits_version
|
||||
self.max_lnbits_version = config.max_lnbits_version
|
||||
self.is_version_compatible = config.is_version_compatible()
|
||||
self.warning = config.warning
|
||||
self.extension_type = config.extension_type
|
||||
self.permissions = config.permissions
|
||||
|
||||
@property
|
||||
def archive_url(self) -> str:
|
||||
if not self.pay_link:
|
||||
|
|
@ -420,6 +435,7 @@ class ExtensionRelease(BaseModel):
|
|||
warning=e.warning,
|
||||
html_url=e.html_url,
|
||||
details_link=e.details_link,
|
||||
extension_type=e.extension_type,
|
||||
pay_link=e.pay_link,
|
||||
paid_features=e.paid_features,
|
||||
repo=e.repo,
|
||||
|
|
@ -447,10 +463,7 @@ class ExtensionRelease(BaseModel):
|
|||
if not config:
|
||||
continue
|
||||
|
||||
release.min_lnbits_version = config.min_lnbits_version
|
||||
release.max_lnbits_version = config.max_lnbits_version
|
||||
release.is_version_compatible = config.is_version_compatible()
|
||||
|
||||
release.apply_config(config)
|
||||
release.icon = icon_to_github_url(f"{org}/{repo}", config.tile)
|
||||
|
||||
return extension_releases
|
||||
|
|
@ -930,6 +943,14 @@ class InstallableExtension(BaseModel):
|
|||
if e.id != ext_id:
|
||||
continue
|
||||
explicit_release = ExtensionRelease.from_explicit_release(url, e)
|
||||
if (
|
||||
explicit_release.extension_type == "wasm"
|
||||
and explicit_release.details_link
|
||||
):
|
||||
config = await ExtensionConfig.fetch_release_config(
|
||||
explicit_release.details_link
|
||||
)
|
||||
explicit_release.apply_config(config)
|
||||
await explicit_release.check_payment_requirements()
|
||||
extension_releases.append(explicit_release)
|
||||
|
||||
|
|
|
|||
|
|
@ -713,6 +713,10 @@ async def get_extension_releases(ext_id: str) -> list[ExtensionRelease]:
|
|||
extension_releases: list[ExtensionRelease] = (
|
||||
await InstallableExtension.get_extension_releases(ext_id)
|
||||
)
|
||||
for release in extension_releases:
|
||||
release.permissions = validate_extension_permissions(
|
||||
ext_id, release.permissions
|
||||
)
|
||||
|
||||
installed_ext = await get_installed_extension(ext_id)
|
||||
if not installed_ext:
|
||||
|
|
|
|||
|
|
@ -21,12 +21,14 @@ from lnbits.core.models import Account, CreateInvoice
|
|||
from lnbits.core.models.extensions import (
|
||||
CreateExtension,
|
||||
CreateExtensionReview,
|
||||
ExplicitRelease,
|
||||
Extension,
|
||||
ExtensionConfig,
|
||||
ExtensionPermission,
|
||||
ExtensionPermissionsUpdate,
|
||||
ExtensionRelease,
|
||||
InstallableExtension,
|
||||
Manifest,
|
||||
PayToEnableInfo,
|
||||
ReleasePaymentInfo,
|
||||
UserExtensionInfo,
|
||||
|
|
@ -173,6 +175,104 @@ async def test_extension_api_install_details_and_release_endpoints(mocker):
|
|||
assert release_info["is_version_compatible"] is True
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_explicit_wasm_release_loads_install_permissions(
|
||||
settings,
|
||||
mocker,
|
||||
):
|
||||
ext_id = f"wasm_{uuid4().hex[:8]}"
|
||||
non_wasm_ext_id = f"python_{uuid4().hex[:8]}"
|
||||
manifest_url = "https://extensions.example/manifest.json"
|
||||
details_link = f"https://extensions.example/{ext_id}/config.json"
|
||||
explicit_release = ExplicitRelease(
|
||||
id=ext_id,
|
||||
name="Explicit WASM Extension",
|
||||
version="1.0.0",
|
||||
archive=f"https://extensions.example/{ext_id}.zip",
|
||||
hash="archive-hash",
|
||||
repo=f"https://github.com/example/{ext_id}",
|
||||
icon=None,
|
||||
short_description="Explicit WASM release",
|
||||
min_lnbits_version="0.1.0",
|
||||
max_lnbits_version=None,
|
||||
html_url=None,
|
||||
warning=None,
|
||||
info_notification=None,
|
||||
critical_notification=None,
|
||||
details_link=details_link,
|
||||
paid_features=None,
|
||||
pay_link=None,
|
||||
extension_type="wasm",
|
||||
)
|
||||
non_wasm_release = explicit_release.copy(
|
||||
update={
|
||||
"id": non_wasm_ext_id,
|
||||
"name": "Explicit Python Extension",
|
||||
"details_link": f"https://extensions.example/{non_wasm_ext_id}/config.json",
|
||||
"extension_type": None,
|
||||
}
|
||||
)
|
||||
config_permissions = [ExtensionPermission(id="wallet.list")]
|
||||
config = ExtensionConfig(
|
||||
name=ext_id,
|
||||
short_description="Explicit WASM release",
|
||||
min_lnbits_version="0.1.0",
|
||||
max_lnbits_version=None,
|
||||
extension_type="wasm",
|
||||
permissions=config_permissions,
|
||||
)
|
||||
|
||||
async def fetch_manifest(url):
|
||||
if url == manifest_url:
|
||||
return Manifest(extensions=[explicit_release, non_wasm_release])
|
||||
return Manifest()
|
||||
|
||||
mocker.patch.object(settings, "lnbits_extensions_manifests", [manifest_url])
|
||||
mocker.patch.object(
|
||||
settings,
|
||||
"lnbits_extensions_builder_manifest_url",
|
||||
"https://extensions.example/builder.json",
|
||||
)
|
||||
mocker.patch.object(
|
||||
InstallableExtension,
|
||||
"fetch_manifest",
|
||||
mocker.AsyncMock(side_effect=fetch_manifest),
|
||||
)
|
||||
fetch_config_mock = mocker.patch.object(
|
||||
ExtensionConfig,
|
||||
"fetch_release_config",
|
||||
mocker.AsyncMock(return_value=config),
|
||||
)
|
||||
|
||||
releases = await InstallableExtension.get_extension_releases(ext_id)
|
||||
|
||||
assert len(releases) == 1
|
||||
assert releases[0].extension_type == "wasm"
|
||||
assert releases[0].permissions == config_permissions
|
||||
fetch_config_mock.assert_awaited_once_with(details_link)
|
||||
|
||||
fetch_config_mock.reset_mock()
|
||||
non_wasm_releases = await InstallableExtension.get_extension_releases(
|
||||
non_wasm_ext_id
|
||||
)
|
||||
assert len(non_wasm_releases) == 1
|
||||
assert non_wasm_releases[0].extension_type is None
|
||||
assert non_wasm_releases[0].permissions == []
|
||||
fetch_config_mock.assert_not_awaited()
|
||||
|
||||
mocker.patch.object(
|
||||
InstallableExtension,
|
||||
"get_extension_releases",
|
||||
mocker.AsyncMock(return_value=releases),
|
||||
)
|
||||
mocker.patch(
|
||||
"lnbits.core.views.extension_api.get_installed_extension",
|
||||
mocker.AsyncMock(return_value=None),
|
||||
)
|
||||
api_releases = await get_extension_releases(ext_id)
|
||||
assert api_releases[0].permissions == config_permissions
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_extension_api_installs_wasm_with_granted_permissions(
|
||||
tmp_path,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue