mirror of
https://github.com/f-droid/fdroidserver.git
synced 2026-09-12 22:22:51 -04:00
Merge branch 'fix-symlinks' into 'master'
Fix symlink handling around triple-t/fastlane metadata Closes #1358 See merge request fdroid/fdroidserver!1858
This commit is contained in:
commit
58efbdfb50
2 files changed
+79
-2
No files matched your search
+33
-2
@@ -1093,6 +1093,34 @@ def insert_funding_yml_donation_links(apps):
|
||||
break
|
||||
|
||||
|
||||
def safe_walk(top, followLinksTo):
|
||||
"""Run os.walk, only following symlinks that stay within followLinksTo.
|
||||
|
||||
Entries whose symlink target escapes the followLinksTo directory
|
||||
are dropped with a warning, so symlinks in an app's source repo
|
||||
cannot leak files from the build host into the published index.
|
||||
"""
|
||||
followLinksTo = os.path.realpath(followLinksTo)
|
||||
|
||||
def _filter(root, names):
|
||||
kept = []
|
||||
for name in names:
|
||||
target = os.path.realpath(os.path.join(root, name))
|
||||
if target == followLinksTo or target.startswith(followLinksTo + os.sep):
|
||||
kept.append(name)
|
||||
else:
|
||||
logging.warning(
|
||||
_('Ignoring "{path}": symlink points outside the app source')
|
||||
.format(path=os.path.join(root, name))
|
||||
)
|
||||
return kept
|
||||
|
||||
for root, dirs, files in os.walk(top, followlinks=True):
|
||||
dirs[:] = _filter(root, dirs)
|
||||
files[:] = _filter(root, files)
|
||||
yield root, dirs, files
|
||||
|
||||
|
||||
def copy_triple_t_store_metadata(apps):
|
||||
"""Include store metadata from the app's source repo.
|
||||
|
||||
@@ -1162,9 +1190,10 @@ def copy_triple_t_store_metadata(apps):
|
||||
# Flutter-style android subdir
|
||||
gradle_subdirs.update(glob.glob(os.path.join('build', packageName, 'android', 'app', 'src', '*', 'play')))
|
||||
|
||||
checkout = os.path.join('build', packageName)
|
||||
for d in sorted(gradle_subdirs):
|
||||
logging.debug('Triple-T Gradle Play Publisher: ' + d)
|
||||
for root, dirs, files in os.walk(d):
|
||||
for root, dirs, files in safe_walk(d, followLinksTo=checkout):
|
||||
segments = root.split('/')
|
||||
if segments[-2] == 'listings' or segments[-2] == 'release-notes':
|
||||
locale = segments[-1]
|
||||
@@ -1262,7 +1291,9 @@ def insert_localized_app_metadata(apps):
|
||||
for srcd in sorted(sourcedirs):
|
||||
if not os.path.isdir(srcd):
|
||||
continue
|
||||
for root, dirs, files in os.walk(srcd):
|
||||
topdir, packageName = srcd.split('/')[:2]
|
||||
checkout = os.path.join(topdir, packageName)
|
||||
for root, dirs, files in safe_walk(srcd, followLinksTo=checkout):
|
||||
segments = root.split('/')
|
||||
packageName = segments[1]
|
||||
if packageName not in apps:
|
||||
|
||||
@@ -653,6 +653,52 @@ class UpdateTest(SetUpTearDownMixin, unittest.TestCase):
|
||||
self.assertEqual(app['localized']['en-US']['name'], 'Goguma')
|
||||
self.assertEqual(app['localized']['en-US']['summary'], 'An IRC client for mobile devices')
|
||||
|
||||
def _triple_t_app(self, packageName):
|
||||
"""Write minimal metadata and return the Triple-T play dir."""
|
||||
os.chdir(self.testdir)
|
||||
Path('metadata').mkdir(exist_ok=True)
|
||||
Path('metadata', packageName + '.yml').write_text(
|
||||
'CurrentVersionCode: 1\n'
|
||||
'Builds:\n - versionCode: 1\n gradle:\n - yes\n'
|
||||
)
|
||||
play = Path('build', packageName, 'src', 'main', 'play')
|
||||
play.mkdir(parents=True)
|
||||
return play
|
||||
|
||||
def _copy_triple_t(self, packageName):
|
||||
config = dict()
|
||||
fdroidserver.common.fill_config_defaults(config)
|
||||
fdroidserver.common.config = config
|
||||
fdroidserver.update.config = config
|
||||
apps = fdroidserver.metadata.read_metadata()
|
||||
fdroidserver.update.copy_triple_t_store_metadata(apps)
|
||||
return apps[packageName].get('localized', {}).get('en-US', {})
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'symlink'), 'requires symlink support')
|
||||
def test_insert_triple_t_symlink_within_checkout(self):
|
||||
"""A listings dir symlinked inside the checkout is still read."""
|
||||
packageName = 'com.example.app'
|
||||
play = self._triple_t_app(packageName)
|
||||
target = Path('build', packageName, 'store-metadata', 'listings', 'en-US')
|
||||
target.mkdir(parents=True)
|
||||
(target / 'full-description.txt').write_text('good description')
|
||||
os.symlink(os.path.relpath(target.parent, play), play / 'listings')
|
||||
self.assertEqual(self._copy_triple_t(packageName).get('description'),
|
||||
'good description')
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'symlink'), 'requires symlink support')
|
||||
def test_insert_triple_t_symlink_outside_checkout(self):
|
||||
"""A listing symlinked outside the checkout must not be published."""
|
||||
packageName = 'com.example.app'
|
||||
play = self._triple_t_app(packageName)
|
||||
en_US = play / 'listings' / 'en-US'
|
||||
en_US.mkdir(parents=True)
|
||||
secret = Path('secret.txt')
|
||||
secret.write_text('SECRET')
|
||||
os.symlink(os.path.abspath(secret), en_US / 'full-description.txt')
|
||||
self.assertNotIn('SECRET',
|
||||
self._copy_triple_t(packageName).get('description', ''))
|
||||
|
||||
def testBadGetsig(self):
|
||||
"""getsig() should still be able to fetch the fingerprint of bad signatures"""
|
||||
# config needed to use jarsigner and keytool
|
||||
|
||||
Reference in new issue
Block a user