[index] Add proper test data and clean up some things for tests

This commit is contained in:
Torsten Grote
2022-04-12 14:00:56 -03:00
parent 1195ee0547
commit d6ce02c922
31 changed files with 5135 additions and 383 deletions

View File

@@ -11,7 +11,6 @@ import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.decodeFromStream
import org.fdroid.index.DEFAULT_LOCALE
import org.fdroid.index.IndexParser
import org.fdroid.index.DEFAULT_LOCALE
import org.fdroid.index.RELEASE_CHANNEL_BETA
import org.fdroid.index.getV1ReleaseChannels
import org.fdroid.index.mapInto
@@ -22,6 +21,18 @@ import org.fdroid.index.v2.LocalizedTextV2
import org.fdroid.index.v2.PackageVersionV2
import java.io.InputStream
/**
* Processes a indexV1 stream and calls the given [indexStreamReceiver] while parsing it.
* Attention: This requires the following canonical top-level order in the JSON
* as produced by `fdroidserver`.
* * repo
* * requests
* * apps
* * packages
*
* Any other order of those elements will produce unexpected results
* or throw [IllegalArgumentException].
*/
@Suppress("DEPRECATION")
@OptIn(ExperimentalSerializationApi::class)
public class IndexV1StreamProcessor(
@@ -29,37 +40,49 @@ public class IndexV1StreamProcessor(
private val certificate: String?,
private val locale: String = DEFAULT_LOCALE,
private val json: Json = IndexParser.json,
private val getAndLogReadBytes: () -> Long? = { null },
) {
public fun process(repoId: Long, inputStream: InputStream) {
json.decodeFromStream(IndexStreamSerializer(repoId), inputStream)
getAndLogReadBytes()
public fun process(inputStream: InputStream) {
json.decodeFromStream(IndexStreamSerializer(), inputStream)
}
private inner class IndexStreamSerializer(val repoId: Long) : KSerializer<IndexV1?> {
private inner class IndexStreamSerializer : KSerializer<IndexV1?> {
override val descriptor = IndexV1.serializer().descriptor
override fun deserialize(decoder: Decoder): IndexV1? {
getAndLogReadBytes()
decoder as? JsonDecoder ?: error("Can be deserialized only by JSON")
decoder.beginStructure(descriptor)
var index = decoder.decodeElementIndex(descriptor)
deserializeRepo(decoder, index, repoId)
index = decoder.decodeElementIndex(descriptor)
deserializeRequests(decoder, index, repoId)
index = decoder.decodeElementIndex(descriptor)
val appDataMap = deserializeApps(decoder, index, repoId)
index = decoder.decodeElementIndex(descriptor)
deserializePackages(decoder, index, repoId, appDataMap)
val index0 = decoder.decodeElementIndex(descriptor)
deserializeRepo(decoder, index0)
val index1 = decoder.decodeElementIndex(descriptor)
if (index1 == DECODE_DONE) {
updateRepoData(emptyMap())
decoder.endStructure(descriptor)
return null
}
deserializeRequests(decoder, index1)
val index2 = decoder.decodeElementIndex(descriptor)
if (index2 == DECODE_DONE) {
updateRepoData(emptyMap())
decoder.endStructure(descriptor)
return null
}
val appDataMap = deserializeApps(decoder, index2)
val index3 = decoder.decodeElementIndex(descriptor)
if (index3 == DECODE_DONE) {
updateRepoData(appDataMap)
decoder.endStructure(descriptor)
return null
}
deserializePackages(decoder, index3, appDataMap)
decoder.endStructure(descriptor)
updateRepoData(appDataMap)
return null
}
private fun deserializeRepo(decoder: JsonDecoder, index: Int, repoId: Long) {
private fun deserializeRepo(decoder: JsonDecoder, index: Int) {
require(index == descriptor.getElementIndex("repo"))
val repo = decoder.decodeSerializableValue(RepoV1.serializer())
val repoV2 = repo.toRepoV2(
@@ -68,32 +91,27 @@ public class IndexV1StreamProcessor(
categories = emptyMap(),
releaseChannels = emptyMap()
)
indexStreamReceiver.receive(repoId, repoV2, repo.version, certificate)
indexStreamReceiver.receive(repoV2, repo.version, certificate)
}
private fun deserializeRequests(decoder: JsonDecoder, index: Int, repoId: Long) {
private fun deserializeRequests(decoder: JsonDecoder, index: Int) {
require(index == descriptor.getElementIndex("requests"))
decoder.decodeSerializableValue(Requests.serializer())
// we ignore the requests here, don't act on them
}
private fun deserializeApps(
decoder: JsonDecoder,
index: Int,
repoId: Long,
): Map<String, AppData> {
private fun deserializeApps(decoder: JsonDecoder, index: Int): Map<String, AppData> {
require(index == descriptor.getElementIndex("apps"))
val appDataMap = HashMap<String, AppData>()
val mapDescriptor = descriptor.getElementDescriptor(index)
val compositeDecoder = decoder.beginStructure(mapDescriptor)
while (true) {
getAndLogReadBytes()
val packageIndex = compositeDecoder.decodeElementIndex(descriptor)
if (packageIndex == DECODE_DONE) break
val appV1 =
decoder.decodeSerializableElement(descriptor, packageIndex, AppV1.serializer())
val appV2 = appV1.toMetadataV2(null, locale)
indexStreamReceiver.receive(repoId, appV1.packageName, appV2)
indexStreamReceiver.receive(appV1.packageName, appV2)
appDataMap[appV1.packageName] = AppData(
antiFeatures = appV1.antiFeatures.associateWith { emptyMap() },
whatsNew = appV1.localized?.mapValuesNotNull { it.value.whatsNew },
@@ -108,20 +126,17 @@ public class IndexV1StreamProcessor(
private fun deserializePackages(
decoder: JsonDecoder,
index: Int,
repoId: Long,
appDataMap: Map<String, AppData>,
) {
require(index == descriptor.getElementIndex("packages"))
val mapDescriptor = descriptor.getElementDescriptor(index)
val compositeDecoder = decoder.beginStructure(mapDescriptor)
while (true) {
getAndLogReadBytes()
val packageIndex = compositeDecoder.decodeElementIndex(descriptor)
if (packageIndex == DECODE_DONE) break
readPackageMapEntry(
decoder = compositeDecoder as JsonDecoder,
index = packageIndex,
repoId = repoId,
appDataMap = appDataMap,
)
}
@@ -131,7 +146,6 @@ public class IndexV1StreamProcessor(
private fun readPackageMapEntry(
decoder: JsonDecoder,
index: Int,
repoId: Long,
appDataMap: Map<String, AppData>,
) {
val packageName = decoder.decodeStringElement(descriptor, index)
@@ -142,7 +156,6 @@ public class IndexV1StreamProcessor(
val compositeDecoder = decoder.beginStructure(listDescriptor)
var isFirstVersion = true
while (true) {
getAndLogReadBytes()
val packageIndex = compositeDecoder.decodeElementIndex(descriptor)
if (packageIndex == DECODE_DONE) break
val packageVersionV1 = decoder.decodeSerializableElement(
@@ -159,17 +172,13 @@ public class IndexV1StreamProcessor(
whatsNew = if (isFirstVersion) appDataMap[packageName]?.whatsNew else null
)
if (isFirstVersion) {
indexStreamReceiver.updateAppMetadata(
repoId,
packageName,
packageVersionV1.signer
)
indexStreamReceiver.updateAppMetadata(packageName, packageVersionV1.signer)
}
isFirstVersion = false
val versionId = packageVersionV2.file.sha256
versions[versionId] = packageVersionV2
}
indexStreamReceiver.receive(repoId, packageName, versions)
indexStreamReceiver.receive(packageName, versions)
compositeDecoder.endStructure(listDescriptor)
}
@@ -177,17 +186,11 @@ public class IndexV1StreamProcessor(
val antiFeatures = HashMap<String, AntiFeatureV2>()
val categories = HashMap<String, CategoryV2>()
appDataMap.values.forEach { appData ->
appData.antiFeatures.keys.mapInto(
antiFeatures,
AntiFeatureV2(name = emptyMap(), description = emptyMap())
)
appData.categories.mapInto(
categories,
CategoryV2(name = emptyMap(), description = emptyMap())
)
appData.antiFeatures.mapInto(antiFeatures)
appData.categories.mapInto(categories)
}
val releaseChannels = getV1ReleaseChannels()
indexStreamReceiver.updateRepo(repoId, antiFeatures, categories, releaseChannels)
indexStreamReceiver.updateRepo(antiFeatures, categories, releaseChannels)
}
override fun serialize(encoder: Encoder, value: IndexV1?) {

View File

@@ -12,26 +12,20 @@ import org.fdroid.index.IndexParser
import java.io.InputStream
@OptIn(ExperimentalSerializationApi::class)
public class IndexStreamProcessor(
private val indexStreamReceiver: IndexStreamReceiver,
public class IndexV2StreamProcessor(
private val indexStreamReceiver: IndexV2StreamReceiver,
private val certificate: String?,
private val json: Json = IndexParser.json,
private val getAndLogReadBytes: () -> Long? = { null },
) {
public fun process(repoId: Long, version: Int, inputStream: InputStream) {
json.decodeFromStream(IndexStreamSerializer(repoId, version), inputStream)
getAndLogReadBytes()
public fun process(version: Int, inputStream: InputStream) {
json.decodeFromStream(IndexStreamSerializer(version), inputStream)
}
private inner class IndexStreamSerializer(
val repoId: Long,
val version: Int,
) : KSerializer<IndexV2?> {
private inner class IndexStreamSerializer(val version: Int) : KSerializer<IndexV2?> {
override val descriptor = IndexV2.serializer().descriptor
override fun deserialize(decoder: Decoder): IndexV2? {
getAndLogReadBytes()
decoder as? JsonDecoder ?: error("Can be deserialized only by JSON")
decoder.beginStructure(descriptor)
@@ -40,49 +34,47 @@ public class IndexStreamProcessor(
when (val startIndex = decoder.decodeElementIndex(descriptor)) {
repoIndex -> {
deserializeRepo(decoder, startIndex, repoId)
deserializeRepo(decoder, startIndex)
val index = decoder.decodeElementIndex(descriptor)
deserializePackages(decoder, index, repoId)
if (index == packagesIndex) deserializePackages(decoder, index)
}
packagesIndex -> {
deserializePackages(decoder, startIndex, repoId)
deserializePackages(decoder, startIndex)
val index = decoder.decodeElementIndex(descriptor)
deserializeRepo(decoder, index, repoId)
if (index == repoIndex) deserializeRepo(decoder, index)
}
else -> error("Unexpected startIndex: $startIndex")
}
decoder.endStructure(descriptor)
indexStreamReceiver.onStreamEnded(repoId)
indexStreamReceiver.onStreamEnded()
return null
}
private fun deserializeRepo(decoder: JsonDecoder, index: Int, repoId: Long) {
private fun deserializeRepo(decoder: JsonDecoder, index: Int) {
require(index == descriptor.getElementIndex("repo"))
val repo = decoder.decodeSerializableValue(RepoV2.serializer())
// TODO this replaces the index and thus removes all data, not good when repo is second
indexStreamReceiver.receive(repoId, repo, version, certificate)
indexStreamReceiver.receive(repo, version, certificate)
}
private fun deserializePackages(decoder: JsonDecoder, index: Int, repoId: Long) {
private fun deserializePackages(decoder: JsonDecoder, index: Int) {
require(index == descriptor.getElementIndex("packages"))
val mapDescriptor = descriptor.getElementDescriptor(index)
val compositeDecoder = decoder.beginStructure(mapDescriptor)
while (true) {
getAndLogReadBytes()
val packageIndex = compositeDecoder.decodeElementIndex(descriptor)
if (packageIndex == CompositeDecoder.DECODE_DONE) break
readMapEntry(compositeDecoder, packageIndex, repoId)
readMapEntry(compositeDecoder, packageIndex)
}
compositeDecoder.endStructure(mapDescriptor)
}
private fun readMapEntry(decoder: CompositeDecoder, index: Int, repoId: Long) {
private fun readMapEntry(decoder: CompositeDecoder, index: Int) {
val packageName = decoder.decodeStringElement(descriptor, index)
decoder.decodeElementIndex(descriptor)
val packageV2 = decoder.decodeSerializableElement(
descriptor, index + 1, PackageV2.serializer()
)
indexStreamReceiver.receive(repoId, packageName, packageV2)
indexStreamReceiver.receive(packageName, packageV2)
}
override fun serialize(encoder: Encoder, value: IndexV2?) {

View File

@@ -1,8 +1,5 @@
package org.fdroid.index.v1
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import org.fdroid.index.v2.AntiFeatureV2
import org.fdroid.index.v2.CategoryV2
import org.fdroid.index.v2.IndexV2
@@ -11,101 +8,85 @@ import org.fdroid.index.v2.PackageV2
import org.fdroid.index.v2.PackageVersionV2
import org.fdroid.index.v2.ReleaseChannelV2
import org.fdroid.index.v2.RepoV2
import org.junit.Assume.assumeTrue
import org.fdroid.test.TestDataEmptyV2
import org.fdroid.test.TestDataMaxV2
import org.fdroid.test.TestDataMidV2
import org.fdroid.test.TestDataMinV2
import org.fdroid.test.v1compat
import org.junit.Test
import java.io.File
import java.io.FileInputStream
import kotlin.test.assertEquals
import kotlin.test.fail
@OptIn(ExperimentalSerializationApi::class)
internal class IndexV1StreamProcessorTest {
private val json = Json
/**
* Tests that indexV1 parsed with a stream receiver matches the indexV2 parsed normally.
*/
@Test
fun testFDroidStreamProcessing() {
val file1 = File("src/commonTest/resources/index-v1.json")
val file2 = File("src/commonTest/resources/index-v2.json")
assumeTrue(file1.isFile)
assumeTrue(file2.isFile)
val indexParsed: IndexV2 = FileInputStream(file2).use { json.decodeFromStream(it) }
fun testEmpty() {
testStreamProcessing("src/sharedTest/resources/index-empty-v1.json",
TestDataEmptyV2.index.v1compat())
}
@Test
fun testMin() {
testStreamProcessing("src/sharedTest/resources/index-min-v1.json",
TestDataMinV2.index.v1compat())
}
@Test
fun testMid() {
testStreamProcessing("src/sharedTest/resources/index-mid-v1.json",
TestDataMidV2.indexCompat)
}
@Test
fun testMax() {
testStreamProcessing("src/sharedTest/resources/index-max-v1.json",
TestDataMaxV2.indexCompat)
}
private fun testStreamProcessing(filePath: String, indexV2: IndexV2) {
val file = File(filePath)
val testStreamReceiver = TestStreamReceiver()
val streamProcessor = IndexV1StreamProcessor(testStreamReceiver, null, json = json)
FileInputStream(file1).use { streamProcessor.process(1, it) }
assertEquals(indexParsed.repo, testStreamReceiver.repo)
assertEquals(indexParsed.packages.size, testStreamReceiver.packages.size)
indexParsed.packages.entries.forEach { (packageName, packageV2) ->
assertEquals(packageV2, testStreamReceiver.packages[packageName])
}
}
@Test
fun testFDroidArchiveStreamProcessing() {
testStreamProcessing("src/commonTest/resources/fdroid-archive/index-v1.json")
}
@Test
fun testGuardianStreamProcessing() {
testStreamProcessing("src/commonTest/resources/guardian/index-v1.json")
}
@Test
fun testIzzyStreamProcessing() {
testStreamProcessing("src/commonTest/resources/izzy/index-v1.json")
}
@Test
fun testWindStreamProcessing() {
testStreamProcessing("src/commonTest/resources/wind/index-v1.json")
}
private fun testStreamProcessing(filePath1: String) {
val file1 = File(filePath1)
assumeTrue(file1.isFile)
val testStreamReceiver = TestStreamReceiver()
val streamProcessor = IndexV1StreamProcessor(testStreamReceiver, null, json = json)
FileInputStream(file1).use { streamProcessor.process(1, it) }
val streamProcessor = IndexV1StreamProcessor(testStreamReceiver, null)
FileInputStream(file).use { streamProcessor.process(it) }
assertEquals(indexV2.repo, testStreamReceiver.repo)
assertEquals(indexV2.packages, testStreamReceiver.packages)
}
@Suppress("DEPRECATION")
private class TestStreamReceiver : IndexV1StreamReceiver {
var repo: RepoV2? = null
val packages = HashMap<String, PackageV2>()
override fun receive(repoId: Long, repo: RepoV2, version: Int, certificate: String?) {
override fun receive(repo: RepoV2, version: Int, certificate: String?) {
this.repo = repo
}
override fun receive(repoId: Long, packageId: String, m: MetadataV2) {
override fun receive(packageId: String, m: MetadataV2) {
packages[packageId] = PackageV2(
metadata = m,
versions = emptyMap(),
)
}
override fun receive(repoId: Long, packageId: String, v: Map<String, PackageVersionV2>) {
override fun receive(packageId: String, v: Map<String, PackageVersionV2>) {
packages[packageId] = packages[packageId]!!.copy(versions = v)
}
override fun updateRepo(
repoId: Long,
antiFeatures: Map<String, AntiFeatureV2>,
categories: Map<String, CategoryV2>,
releaseChannels: Map<String, ReleaseChannelV2>,
) {
repo = repo!!.copy(
repo = repo?.copy(
antiFeatures = antiFeatures,
categories = categories,
releaseChannels = releaseChannels,
)
) ?: fail()
}
override fun updateAppMetadata(repoId: Long, packageId: String, preferredSigner: String?) {
override fun updateAppMetadata(packageId: String, preferredSigner: String?) {
val currentPackage = packages[packageId] ?: fail()
packages[packageId] = currentPackage.copy(
metadata = currentPackage.metadata.copy(preferredSigner = preferredSigner),

View File

@@ -1,26 +0,0 @@
package org.fdroid.index.v1
import io.ktor.utils.io.jvm.javaio.toByteReadChannel
import io.ktor.utils.io.jvm.javaio.toInputStream
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import org.junit.Assume.assumeTrue
import java.io.File
import java.io.FileInputStream
import kotlin.test.Test
internal class StreamTest {
@Test
@OptIn(ExperimentalSerializationApi::class)
fun test() = runBlocking {
val file = File("src/commonTest/resources/index-v1.json")
assumeTrue(file.isFile)
val byteChannel = FileInputStream(file).toByteReadChannel()
val index = Json.decodeFromStream<IndexV1>(byteChannel.toInputStream())
}
}

View File

@@ -1,121 +0,0 @@
package org.fdroid.index.v2
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
import org.junit.Assume.assumeTrue
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.test.fail
private const val INDEX_V2 = "src/commonTest/resources/index-v2.json"
@OptIn(ExperimentalSerializationApi::class)
internal class IndexStreamProcessorTest {
@get:Rule
var folder: TemporaryFolder = TemporaryFolder()
private val json = Json
/**
* Tests that index parsed with a stream receiver matches the index parsed normally.
*/
@Test
fun testStreamProcessing() {
val file = File(INDEX_V2)
assumeTrue(file.isFile)
val indexParsed: IndexV2 = FileInputStream(file).use { json.decodeFromStream(it) }
val testStreamReceiver = TestStreamReceiver()
val certificate = "foo bar"
val streamProcessor = IndexStreamProcessor(testStreamReceiver, certificate, json)
FileInputStream(file).use { streamProcessor.process(1, 42, it) }
assertEquals(indexParsed.repo, testStreamReceiver.repo)
assertTrue(testStreamReceiver.calledOnStreamEnded)
assertEquals(certificate, testStreamReceiver.certificate)
assertEquals(indexParsed.packages.size, testStreamReceiver.packages.size)
indexParsed.packages.entries.forEach { (packageName, packageV2) ->
assertEquals(packageV2, testStreamReceiver.packages[packageName])
}
}
/**
* Tests that that [IndexStreamProcessor] can handle a re-ordered index,
* i.e. repo only after packages.
*/
@Test
fun testReorderedStreamProcessing() {
val file = File(INDEX_V2)
assumeTrue(file.isFile)
val indexParsed: IndexV2 = FileInputStream(file).use { json.decodeFromStream(it) }
val newFile = folder.newFile()
// write out parsed index in reverse order (repo after packages)
FileOutputStream(newFile).use { outputStream ->
outputStream.write("{ \"packages\": ".encodeToByteArray())
json.encodeToStream(indexParsed.packages, outputStream)
outputStream.write(", \"repo\": ".encodeToByteArray())
json.encodeToStream(indexParsed.repo, outputStream)
outputStream.write("}".encodeToByteArray())
}
val testStreamReceiver = ReorderedTestStreamReceiver()
val certificate = "foo bar"
val streamProcessor = IndexStreamProcessor(testStreamReceiver, certificate, json)
FileInputStream(newFile).use { streamProcessor.process(1, 42, it) }
assertTrue(testStreamReceiver.repoReceived)
assertTrue(testStreamReceiver.calledOnStreamEnded)
assertEquals(indexParsed.repo, testStreamReceiver.repo)
assertEquals(certificate, testStreamReceiver.certificate)
assertEquals(indexParsed.packages.size, testStreamReceiver.packages.size)
indexParsed.packages.entries.forEach { (packageName, packageV2) ->
assertEquals(packageV2, testStreamReceiver.packages[packageName])
}
}
private open class TestStreamReceiver : IndexStreamReceiver {
var repo: RepoV2? = null
var certificate: String? = null
val packages = HashMap<String, PackageV2>()
var calledOnStreamEnded: Boolean = false
override fun receive(repoId: Long, repo: RepoV2, version: Int, certificate: String?) {
this.repo = repo
this.certificate = certificate
}
override fun receive(repoId: Long, packageId: String, p: PackageV2) {
packages[packageId] = p
}
override fun onStreamEnded(repoId: Long) {
if (calledOnStreamEnded) fail()
calledOnStreamEnded = true
}
}
private class ReorderedTestStreamReceiver : TestStreamReceiver() {
var repoReceived: Boolean = false
override fun receive(repoId: Long, repo: RepoV2, version: Int, certificate: String?) {
super.receive(repoId, repo, version, certificate)
assertFalse(repoReceived)
repoReceived = true
}
override fun receive(repoId: Long, packageId: String, p: PackageV2) {
super.receive(repoId, packageId, p)
assertFalse(repoReceived)
}
}
}

View File

@@ -0,0 +1,87 @@
package org.fdroid.index.v2
import kotlinx.serialization.ExperimentalSerializationApi
import org.fdroid.test.TestDataEmptyV2
import org.fdroid.test.TestDataMaxV2
import org.fdroid.test.TestDataMidV2
import org.fdroid.test.TestDataMinV2
import org.fdroid.test.TestUtils.getRandomString
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import java.io.File
import java.io.FileInputStream
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail
@OptIn(ExperimentalSerializationApi::class)
internal class IndexV2StreamProcessorTest {
@get:Rule
var folder: TemporaryFolder = TemporaryFolder()
@Test
fun testEmpty() {
testStreamProcessing("src/sharedTest/resources/index-empty-v2.json", TestDataEmptyV2.index)
}
@Test
fun testMin() {
testStreamProcessing("src/sharedTest/resources/index-min-v2.json", TestDataMinV2.index)
}
@Test
fun testMinReordered() {
testStreamProcessing("src/sharedTest/resources/index-min-reordered-v2.json",
TestDataMinV2.index)
}
@Test
fun testMid() {
testStreamProcessing("src/sharedTest/resources/index-mid-v2.json", TestDataMidV2.index)
}
@Test
fun testMax() {
testStreamProcessing("src/sharedTest/resources/index-max-v2.json", TestDataMaxV2.index)
}
/**
* Tests that index parsed with a stream receiver is equal to the expected test data.
*/
fun testStreamProcessing(filePath: String, index: IndexV2) {
val file = File(filePath)
val testStreamReceiver = TestStreamReceiver()
val certificate = getRandomString()
val streamProcessor = IndexV2StreamProcessor(testStreamReceiver, certificate)
FileInputStream(file).use { streamProcessor.process(42, it) }
assertTrue(testStreamReceiver.calledOnStreamEnded)
assertEquals(index.repo, testStreamReceiver.repo)
assertEquals(certificate, testStreamReceiver.certificate)
assertEquals(index.packages, testStreamReceiver.packages)
}
private open class TestStreamReceiver : IndexV2StreamReceiver {
var repo: RepoV2? = null
var certificate: String? = null
val packages = HashMap<String, PackageV2>()
var calledOnStreamEnded: Boolean = false
override fun receive(repo: RepoV2, version: Int, certificate: String?) {
this.repo = repo
this.certificate = certificate
}
override fun receive(packageId: String, p: PackageV2) {
packages[packageId] = p
}
override fun onStreamEnded() {
if (calledOnStreamEnded) fail()
calledOnStreamEnded = true
}
}
}

View File

@@ -1,7 +1,7 @@
package org.fdroid.index.v2
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import org.fdroid.index.IndexParser.json
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
@@ -15,14 +15,14 @@ internal class ReflectionDifferTest {
put("en", "bar")
put("de-DE", "foo bar")
}
val json = """
val jsonInput = """
{
"de": "foo",
"en": null,
"en-US": "bar"
}
""".trimIndent()
val diff = Json.parseToJsonElement(json).jsonObject
val diff = json.parseToJsonElement(jsonInput).jsonObject
val result = ReflectionDiffer.applyDiff(old, diff)
assertEquals(3, result.size)
@@ -38,13 +38,13 @@ internal class ReflectionDifferTest {
sha256 = "bar",
size = Random.nextLong()
)
val json = """
val jsonInput = """
{
"name": "foo bar",
"size": null
}
""".trimIndent()
val diff = Json.parseToJsonElement(json).jsonObject
val diff = json.parseToJsonElement(jsonInput).jsonObject
val result = ReflectionDiffer.applyDiff(old, diff)
assertEquals("foo bar", result.name)

View File

@@ -39,14 +39,8 @@ public class IndexConverter(
it.hash to it.toPackageVersionV2(versionReleaseChannels, appAntiFeatures, wn)
} ?: emptyMap(),
)
appAntiFeatures.keys.mapInto(
antiFeatures,
AntiFeatureV2(name = emptyMap(), description = emptyMap())
)
app.categories.mapInto(
categories,
CategoryV2(name = emptyMap(), description = emptyMap())
)
appAntiFeatures.mapInto(antiFeatures)
app.categories.mapInto(categories)
packagesV2[app.packageName] = packageV2
}
return IndexV2(
@@ -62,14 +56,29 @@ public class IndexConverter(
}
internal fun <T> Collection<String>.mapInto(map: HashMap<String, T>, value: T) {
internal fun <T> Collection<String>.mapInto(map: HashMap<String, T>, valueGetter: (String) -> T) {
forEach { key ->
if (!map.containsKey(key)) map[key] = value
if (!map.containsKey(key)) map[key] = valueGetter(key)
}
}
internal fun getV1ReleaseChannels() = mapOf(
RELEASE_CHANNEL_BETA to ReleaseChannelV2(emptyMap(), emptyMap())
internal fun List<String>.mapInto(map: HashMap<String, CategoryV2>) {
mapInto(map) { key ->
CategoryV2(name = mapOf(DEFAULT_LOCALE to key))
}
}
internal fun Map<String, LocalizedTextV2>.mapInto(map: HashMap<String, AntiFeatureV2>) {
keys.mapInto(map) { key ->
AntiFeatureV2(name = mapOf(DEFAULT_LOCALE to key))
}
}
public fun getV1ReleaseChannels(): Map<String, ReleaseChannelV2> = mapOf(
RELEASE_CHANNEL_BETA to ReleaseChannelV2(
name = mapOf(DEFAULT_LOCALE to RELEASE_CHANNEL_BETA),
description = emptyMap(),
)
)
internal fun <T> Map<String, Localized>.mapValuesNotNull(

View File

@@ -78,8 +78,8 @@ public data class AppV1(
litecoin = litecoin,
flattrID = flattrID,
).takeIf { !it.isNull },
icon = icon?.let { mapOf(locale to FileV2("/icons/$it")) }
?: localized.toLocalizedFileV2 { it.icon },
icon = localized.toLocalizedFileV2 { it.icon }
?: icon?.let { mapOf(locale to FileV2("/icons/$it")) },
featureGraphic = localized.toLocalizedFileV2 { it.featureGraphic },
promoGraphic = localized.toLocalizedFileV2 { it.promoGraphic },
tvBanner = localized.toLocalizedFileV2 { it.tvBanner },

View File

@@ -13,9 +13,9 @@ import org.fdroid.index.v2.RepoV2
@Serializable
public data class IndexV1(
val repo: RepoV1,
val requests: Requests,
val apps: List<AppV1>,
val packages: Map<String, List<PackageV1>>,
val requests: Requests = Requests(emptyList(), emptyList()),
val apps: List<AppV1> = emptyList(),
val packages: Map<String, List<PackageV1>> = emptyMap(),
)
@Serializable

View File

@@ -10,12 +10,11 @@ import org.fdroid.index.v2.RepoV2
@Deprecated("Use IndexV2 instead")
public interface IndexV1StreamReceiver {
public fun receive(repoId: Long, repo: RepoV2, version: Int, certificate: String?)
public fun receive(repoId: Long, packageId: String, m: MetadataV2)
public fun receive(repoId: Long, packageId: String, v: Map<String, PackageVersionV2>)
public fun receive(repo: RepoV2, version: Int, certificate: String?)
public fun receive(packageId: String, m: MetadataV2)
public fun receive(packageId: String, v: Map<String, PackageVersionV2>)
public fun updateRepo(
repoId: Long,
antiFeatures: Map<String, AntiFeatureV2>,
categories: Map<String, CategoryV2>,
releaseChannels: Map<String, ReleaseChannelV2>,
@@ -25,6 +24,6 @@ public interface IndexV1StreamReceiver {
* Updates [MetadataV2.preferredSigner] with the given [preferredSigner]
* for the given [packageId].
*/
public fun updateAppMetadata(repoId: Long, packageId: String, preferredSigner: String?)
public fun updateAppMetadata(packageId: String, preferredSigner: String?)
}

View File

@@ -1,12 +1,16 @@
package org.fdroid.index.v1
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.descriptors.element
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.encoding.encodeCollection
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.intOrNull
import kotlinx.serialization.json.jsonArray
@@ -84,7 +88,7 @@ public data class PackageV1(
@Serializable(with = PermissionV1Serializer::class)
public data class PermissionV1(
val name: String,
val maxSdk: Int?,
val maxSdk: Int? = null,
)
internal class PermissionV1Serializer : KSerializer<PermissionV1> {
@@ -102,8 +106,12 @@ internal class PermissionV1Serializer : KSerializer<PermissionV1> {
return PermissionV1(name, maxSdk)
}
@OptIn(ExperimentalSerializationApi::class)
override fun serialize(encoder: Encoder, value: PermissionV1) {
TODO("Not yet implemented")
encoder.encodeCollection(JsonArray.serializer().descriptor, 2) {
encodeStringElement(descriptor, 0, value.name)
encodeNullableSerializableElement(descriptor, 1, Int.serializer(), value.maxSdk)
}
}
}

View File

@@ -1,9 +0,0 @@
package org.fdroid.index.v2
public interface IndexStreamReceiver {
public fun receive(repoId: Long, repo: RepoV2, version: Int, certificate: String?)
public fun receive(repoId: Long, packageId: String, p: PackageV2)
public fun onStreamEnded(repoId: Long)
}

View File

@@ -21,7 +21,7 @@ public data class FileV2(
@Serializable
public data class IndexV2(
val repo: RepoV2,
val packages: Map<String, PackageV2>,
val packages: Map<String, PackageV2> = emptyMap(),
)
@Serializable

View File

@@ -0,0 +1,22 @@
package org.fdroid.index.v2
public interface IndexV2StreamReceiver {
/**
* Receives the [RepoV2] from the index stream.
* Attention: This might get called after receiving packages.
*/
public fun receive(repo: RepoV2, version: Int, certificate: String?)
/**
* Receives one [PackageV2] from the index stream.
* This is called once for each package in the index.
*/
public fun receive(packageId: String, p: PackageV2)
/**
* Called when the stream has been processed to its end.
*/
public fun onStreamEnded()
}

View File

@@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
@Serializable
public data class PackageV2(
val metadata: MetadataV2,
val versions: Map<String, PackageVersionV2>,
val versions: Map<String, PackageVersionV2> = emptyMap(),
)
@Serializable

View File

@@ -1,40 +1,51 @@
package org.fdroid.index
import com.goncalossilva.resources.Resource
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.fdroid.index.v1.IndexV1
import org.fdroid.index.IndexParser.parseV1
import org.fdroid.index.v2.IndexV2
import org.junit.Assume.assumeTrue
import org.fdroid.test.TestDataEmptyV2
import org.fdroid.test.TestDataMaxV2
import org.fdroid.test.TestDataMidV2
import org.fdroid.test.TestDataMinV2
import org.fdroid.test.TestUtils.sorted
import org.fdroid.test.v1compat
import kotlin.test.Test
import kotlin.test.assertEquals
internal class IndexConverterTest {
@Test
fun testToIndexV2() {
val res1 = Resource("src/commonTest/resources/index-v1.json")
assumeTrue(res1.exists())
val indexV1Str = res1.readText()
val indexV1 = Json.decodeFromString<IndexV1>(indexV1Str)
fun testEmpty() {
testConversation("src/sharedTest/resources/index-empty-v1.json",
TestDataEmptyV2.index.v1compat())
}
@Test
fun testMin() {
testConversation("src/sharedTest/resources/index-min-v1.json",
TestDataMinV2.index.v1compat())
}
@Test
fun testMid() {
testConversation("src/sharedTest/resources/index-mid-v1.json",
TestDataMidV2.indexCompat)
}
@Test
fun testMax() {
testConversation("src/sharedTest/resources/index-max-v1.json",
TestDataMaxV2.indexCompat)
}
private fun testConversation(file: String, expectedIndex: IndexV2) {
val indexV1Res = Resource(file)
val indexV1Str = indexV1Res.readText()
val indexV1 = parseV1(indexV1Str)
val v2 = IndexConverter().toIndexV2(indexV1)
val res2 = Resource("src/commonTest/resources/index-v2.json")
assumeTrue(res2.exists())
val indexV2Str = res2.readText()
val indexV2 = Json.decodeFromString<IndexV2>(indexV2Str)
assertEquals(
indexV2.repo,
v2.repo.copy(
antiFeatures = emptyMap(), categories = emptyMap(), releaseChannels = emptyMap()
)
) // TODO remove copies when test data is fixed
assertEquals(indexV2.packages.size, v2.packages.size)
indexV2.packages.keys.forEach { packageName ->
assertEquals(indexV2.packages[packageName], v2.packages[packageName])
}
assertEquals(expectedIndex.sorted(), v2.sorted())
}
}

View File

@@ -1,40 +1,46 @@
package org.fdroid.index.v1
import com.goncalossilva.resources.Resource
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.junit.Assume.assumeTrue
import org.fdroid.index.IndexParser.parseV1
import org.fdroid.test.TestDataEmptyV1
import org.fdroid.test.TestDataMaxV1
import org.fdroid.test.TestDataMidV1
import org.fdroid.test.TestDataMinV1
import kotlin.test.Test
import kotlin.test.assertEquals
internal class IndexV1Test {
@Test
fun testIndexV1() {
val indexRes = Resource("src/commonTest/resources/index-v1.json")
assumeTrue(indexRes.exists())
fun testIndexEmptyV1() {
val indexRes = Resource("src/sharedTest/resources/index-empty-v1.json")
val indexStr = indexRes.readText()
val index = Json.decodeFromString<IndexV1>(indexStr)
val index = parseV1(indexStr)
assertEquals(TestDataEmptyV1.index, index)
}
val indexArchiveRes = Resource("src/commonTest/resources/fdroid-archive/index-v1.json")
assumeTrue(indexArchiveRes.exists())
val indexArchiveStr = indexArchiveRes.readText()
assumeTrue(indexRes.exists())
Json.decodeFromString<IndexV1>(indexArchiveStr)
@Test
fun testIndexMinV1() {
val indexRes = Resource("src/sharedTest/resources/index-min-v1.json")
val indexStr = indexRes.readText()
val index = parseV1(indexStr)
assertEquals(TestDataMinV1.index, index)
}
val indexGuardianRes = Resource("src/commonTest/resources/guardian/index-v1.json")
assumeTrue(indexGuardianRes.exists())
val indexGuardianStr = indexGuardianRes.readText()
Json.decodeFromString<IndexV1>(indexGuardianStr)
@Test
fun testIndexMidV1() {
val indexRes = Resource("src/sharedTest/resources/index-mid-v1.json")
val indexStr = indexRes.readText()
val index = parseV1(indexStr)
assertEquals(TestDataMidV1.index, index)
}
val indexIzzyRes = Resource("src/commonTest/resources/izzy/index-v1.json")
assumeTrue(indexIzzyRes.exists())
val indexIzzyStr = indexIzzyRes.readText()
Json.decodeFromString<IndexV1>(indexIzzyStr)
val indexWindRes = Resource("src/commonTest/resources/wind/index-v1.json")
assumeTrue(indexWindRes.exists())
val indexWindStr = indexWindRes.readText()
Json.decodeFromString<IndexV1>(indexWindStr)
@Test
fun testIndexMaxV1() {
val indexRes = Resource("src/sharedTest/resources/index-max-v1.json")
val indexStr = indexRes.readText()
val index = parseV1(indexStr)
assertEquals(TestDataMaxV1.index, index)
}
}

View File

@@ -1,33 +1,48 @@
package org.fdroid.index.v2
import com.goncalossilva.resources.Resource
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.junit.Assume.assumeTrue
import org.fdroid.index.IndexParser.parseV2
import org.fdroid.test.TestDataEmptyV2
import org.fdroid.test.TestDataMaxV2
import org.fdroid.test.TestDataMidV2
import org.fdroid.test.TestDataMinV2
import kotlin.test.Test
import kotlin.test.assertEquals
internal class IndexV2Test {
@Test
fun testIndexV2() {
val entryRes = Resource("src/commonTest/resources/entry.json")
assumeTrue(entryRes.exists())
val entryStr = entryRes.readText()
val entry = Json.decodeFromString<EntryV2>(entryStr)
val indexRes = Resource("src/commonTest/resources/index-v2.json")
assumeTrue(indexRes.exists())
val indexStr = indexRes.readText()
val index = Json.decodeFromString<IndexV2>(indexStr)
fun testEmpty() {
testIndexEquality("src/sharedTest/resources/index-empty-v2.json", TestDataEmptyV2.index)
}
@Test
fun testDiffV2() {
// val diff1Res = Resource("src/commonTest/resources/tmp.json")
// assumeTrue(diff1Res.exists())
// val diff1Str = diff1Res.readText()
// val diff1 = Json.decodeFromString<DiffV2>(diff1Str)
// println(diff1)
fun testMin() {
testIndexEquality("src/sharedTest/resources/index-min-v2.json", TestDataMinV2.index)
}
@Test
fun testMinReordered() {
testIndexEquality("src/sharedTest/resources/index-min-reordered-v2.json",
TestDataMinV2.index)
}
@Test
fun testMid() {
testIndexEquality("src/sharedTest/resources/index-mid-v2.json", TestDataMidV2.index)
}
@Test
fun testMax() {
testIndexEquality("src/sharedTest/resources/index-max-v2.json", TestDataMaxV2.index)
}
private fun testIndexEquality(file: String, expectedIndex: IndexV2) {
val indexV2Res = Resource(file)
val indexV2Str = indexV2Res.readText()
val indexV2 = parseV2(indexV2Str)
assertEquals(expectedIndex, indexV2)
}
}

View File

@@ -0,0 +1,615 @@
package org.fdroid.test
import org.fdroid.index.v1.AppV1
import org.fdroid.index.v1.IndexV1
import org.fdroid.index.v1.Localized
import org.fdroid.index.v1.PackageV1
import org.fdroid.index.v1.PermissionV1
import org.fdroid.index.v1.RepoV1
import org.fdroid.index.v1.Requests
internal object TestDataEmptyV1 {
val repo = RepoV1(
timestamp = 23,
version = 23,
name = "EmptyV1",
icon = "empty-v1.png",
address = "https://empty-v1.org",
description = "This is a repo with empty data.",
)
val index = IndexV1(
repo = repo,
)
}
internal object TestDataMinV1 {
val repo = RepoV1(
timestamp = 42,
version = 1,
name = "MinV1",
icon = "min-v1.png",
address = "https://min-v1.org",
description = "This is a repo with minimal data.",
)
const val packageName = "org.fdroid.min1"
val app = AppV1(
packageName = packageName,
categories = emptyList(),
antiFeatures = emptyList(),
license = "",
)
val apps = listOf(app)
val version = PackageV1(
packageName = packageName,
apkName = "${packageName}_23.apk",
hash = "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
hashType = "sha256",
size = 1337,
versionName = "0",
)
val versions = listOf(version)
val packages = mapOf(packageName to versions)
val index = IndexV1(
repo = repo,
requests = Requests(emptyList(), emptyList()),
apps = apps,
packages = packages,
)
}
internal object TestDataMidV1 {
val repo = RepoV1(
timestamp = 1337,
version = 1,
maxAge = 23,
name = "MidV1",
icon = "mid-v1.png",
address = "https://mid-v1.org",
description = "This is a repo with medium data.",
mirrors = listOf("https://mid-v1.com"),
)
const val packageName1 = TestDataMinV1.packageName
const val packageName2 = "org.fdroid.fdroid"
val categories = listOf("Cat1", "Cat2", "Cat3")
val app1 = TestDataMinV1.app.copy(
packageName = packageName1,
categories = listOf(categories[0]),
antiFeatures = listOf("AntiFeature"),
summary = "App1 summary",
description = "App1 description",
name = "App1",
authorName = "App1 author",
license = "GPLv3",
webSite = "http://min1.test.org",
added = 1234567890,
icon = "icon-min1.png",
lastUpdated = 1234567891,
localized = mapOf(
"de" to Localized(
description = "App1 beschreibung",
name = "app 1 name",
summary = "App1 Zusammenfassung",
),
),
)
val app2 = AppV1(
categories = listOf("System"),
antiFeatures = emptyList(),
changelog = "https://gitlab.com/fdroid/fdroidclient/raw/HEAD/CHANGELOG.md",
translation = "https://hosted.weblate.org/projects/f-droid/f-droid",
issueTracker = "https://gitlab.com/fdroid/fdroidclient/issues",
sourceCode = "https://gitlab.com/fdroid/fdroidclient",
donate = "https://f-droid.org/donate",
liberapayID = "27859",
openCollective = "F-Droid-Euro",
flattrID = "343053",
suggestedVersionName = "1.14",
suggestedVersionCode = "1014050",
license = "GPL-3.0-or-later",
webSite = "https://f-droid.org",
added = 1295222400000,
icon = "org.fdroid.fdroid.1014050.png",
packageName = "org.fdroid.fdroid",
lastUpdated = 1643250075000,
localized = mapOf(
"af" to Localized(
description = "F-Droid is 'n installeerbare katalogus van gratis sagteware",
name = "-درويد",
summary = "متجر التطبيقات الذي يحترم الحرية والخصوصية)",
),
"be" to Localized(
name = "F-Droid",
summary = "Крама праграм, якая паважае свабоду і прыватнасць",
),
"bg" to Localized(
summary = "Магазинът за приложения, който уважава независимостта и поверителността",
),
"bn" to Localized(
name = "এফ-ড্রয়েড",
summary = "যে অ্যাপ স্টোর স্বাধীনতা ও গোপনীয়তা সম্মান করে"
),
"bo" to Localized(
description = "ཨེཕ་རོཌ་ནི་ཨེན་ཀྲོཌ་བབ་སྟེགས་ཀྱི་ཆེད་དུ་FOSS",
summary = "རང་དབང་དང་གསང་དོན་ལ་གུས་བརྩི་ཞུས་མཁན་གྱི་མཉེན་ཆས་ཉར་ཚགས་ཁང་།",
),
"ca" to Localized(
description = "F-Droid és un catàleg instal·lable d'aplicacions de software lliure",
name = "F-Droid",
summary = "La botiga d'aplicacions que respecta la llibertat i la privacitat",
),
"cs" to Localized(
description = "F-Droid je instalovatelný katalog softwarových libre",
name = "F-Droid",
summary = "Zdroj aplikací který respektuje vaši svobodu a soukromí",
),
"cy" to Localized(
description = "Mae F-Droid yn gatalog y gellir ei osod o apiau meddalwedd rhydd" +
"ar gyfer Android.",
name = "F-Droid",
summary = "Yr ystorfa apiau sy'n parchu rhyddid a phreifatrwydd",
),
"de" to Localized(
description = "F-Droid ist ein installierbarer Katalog mit Libre Software" +
"Android-Apps.",
summary = "Der App-Store, der Freiheit und Privatsphäre respektiert",
),
"el" to Localized(
description = "Το F-Droid είναι ένας κατάλογος εφαρμογών ελεύθερου λογισμικού",
name = "F-Droid",
summary = "Το κατάστημα εφαρμογών που σέβεται την ελευθερία και την ιδιωτικότητα",
),
"en-US" to Localized(
description = "F-Droid is an installable catalogue of libre software",
name = "F-Droid",
whatsNew = "* Overhaul Share menu to use built-in options like Nearby",
phoneScreenshots = listOf(
"screenshot-app-details.png",
"screenshot-dark-details.png",
"screenshot-dark-home.png",
"screenshot-dark-knownvuln.png",
"screenshot-knownvuln.png",
"screenshot-search.png",
"screenshot-updates.png",
),
featureGraphic = "featureGraphic_PTun9TO4cMFOeiqbvQSrkdcxNUcOFQCymMIaj9UJOAY=.jpg",
summary = "The app store that respects freedom and privacy",
),
"eo" to Localized(
description = "F-Droid estas instalebla katalogo de liberaj aplikaĵoj por Android.",
name = "F-Droid",
whatsNew = "• rekonstruita menuo “Kunhavigi” por uzi enkonstruitajn eblojn, ekz.",
summary = "Aplikaĵa vendejo respektanta liberecon kaj privatecon",
),
),
)
val apps = listOf(app1, app2)
val version1_1 = TestDataMinV1.version.copy(
added = 2342,
apkName = "${packageName1}_23_2.apk",
size = 1338,
srcName = "${packageName1}_23_2.zip",
usesPermission = listOf(PermissionV1("perm")),
usesPermission23 = emptyList(),
versionCode = 1,
versionName = "1",
nativeCode = listOf("x86"),
features = listOf("feature"),
antiFeatures = listOf("anti-feature"),
)
val version1_2 = PackageV1(
packageName = packageName1,
apkName = "${packageName1}_42.apk",
hash = "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
hashType = "sha256",
minSdkVersion = 21,
maxSdkVersion = 4568,
targetSdkVersion = 32,
sig = "old",
signer = "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
size = 1337,
srcName = "${packageName1}_42.zip",
versionCode = 24,
versionName = "24",
)
val version2_1 = PackageV1(
added = 1643250075000,
apkName = "org.fdroid.fdroid_1014050.apk",
hash = "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06",
hashType = "sha256",
minSdkVersion = 22,
targetSdkVersion = 25,
packageName = "org.fdroid.fdroid",
sig = "9063aaadfff9cfd811a9c72fb5012f28",
signer = "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
size = 8165518,
srcName = "org.fdroid.fdroid_1014050_src.tar.gz",
usesPermission = listOf(
PermissionV1(name = "android.permission.INTERNET"),
PermissionV1(name = "android.permission.ACCESS_NETWORK_STATE"),
PermissionV1(name = "android.permission.ACCESS_WIFI_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_MULTICAST_STATE"),
PermissionV1(name = "android.permission.CHANGE_NETWORK_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_STATE"),
PermissionV1(name = "android.permission.BLUETOOTH"),
PermissionV1(name = "android.permission.BLUETOOTH_ADMIN"),
PermissionV1(name = "android.permission.RECEIVE_BOOT_COMPLETED"),
PermissionV1(name = "android.permission.READ_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_SETTINGS"),
PermissionV1(name = "android.permission.NFC"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = 22),
PermissionV1(name = "android.permission.WAKE_LOCK"),
PermissionV1(name = "android.permission.FOREGROUND_SERVICE")
),
usesPermission23 = listOf(PermissionV1(name = "android.permission.ACCESS_COARSE_LOCATION")),
versionCode = 1014050,
versionName = "1.14",
)
val version2_2 = PackageV1(
added = 1642785071000,
apkName = "org.fdroid.fdroid_1014005.apk",
hash = "b4282febf5558d43c7c51a00478961f6df1b6d59e0a6674974cdacb792683e5d",
hashType = "sha256",
minSdkVersion = 22,
targetSdkVersion = 25,
packageName = "org.fdroid.fdroid",
sig = "9063aaadfff9cfd811a9c72fb5012f28",
signer = "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
size = 8382606,
srcName = "org.fdroid.fdroid_1014005_src.tar.gz",
usesPermission = listOf(
PermissionV1(name = "android.permission.INTERNET"),
PermissionV1(name = "android.permission.ACCESS_NETWORK_STATE"),
PermissionV1(name = "android.permission.ACCESS_WIFI_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_MULTICAST_STATE"),
PermissionV1(name = "android.permission.CHANGE_NETWORK_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_STATE"),
PermissionV1(name = "android.permission.BLUETOOTH"),
PermissionV1(name = "android.permission.BLUETOOTH_ADMIN"),
PermissionV1(name = "android.permission.RECEIVE_BOOT_COMPLETED"),
PermissionV1(name = "android.permission.READ_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_SETTINGS"),
PermissionV1(name = "android.permission.NFC"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = 22),
PermissionV1(name = "android.permission.WAKE_LOCK"),
PermissionV1(name = "android.permission.FOREGROUND_SERVICE")
),
usesPermission23 = listOf(PermissionV1(name = "android.permission.ACCESS_COARSE_LOCATION")),
versionCode = 1014005,
versionName = "1.14-alpha5",
nativeCode = listOf("fakeNativeCode"),
features = listOf("fake feature"),
antiFeatures = listOf("FakeAntiFeature")
)
val version2_3 = PackageV1(
added = 1635169849000,
apkName = "org.fdroid.fdroid_1014003.apk",
hash = "c062a9642fde08aacabbfa4cab1ab5773c83f4e6b81551ffd92027d2b20f37d3",
hashType = "sha256",
minSdkVersion = 22,
targetSdkVersion = 25,
packageName = "org.fdroid.fdroid",
sig = "9063aaadfff9cfd811a9c72fb5012f28",
signer = "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
size = 8276110,
srcName = "org.fdroid.fdroid_1014003_src.tar.gz",
usesPermission = listOf(
PermissionV1(name = "android.permission.INTERNET"),
PermissionV1(name = "android.permission.ACCESS_NETWORK_STATE"),
PermissionV1(name = "android.permission.ACCESS_WIFI_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_MULTICAST_STATE"),
PermissionV1(name = "android.permission.CHANGE_NETWORK_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_STATE"),
PermissionV1(name = "android.permission.BLUETOOTH"),
PermissionV1(name = "android.permission.BLUETOOTH_ADMIN"),
PermissionV1(name = "android.permission.RECEIVE_BOOT_COMPLETED"),
PermissionV1(name = "android.permission.READ_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_SETTINGS"),
PermissionV1(name = "android.permission.NFC"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = 22),
PermissionV1(name = "android.permission.WAKE_LOCK"),
PermissionV1(name = "android.permission.FOREGROUND_SERVICE"),
),
usesPermission23 = listOf(PermissionV1(name = "android.permission.ACCESS_COARSE_LOCATION")),
versionCode = 1014003,
versionName = "1.14-alpha3",
)
val version2_4 = PackageV1(
added = 1632281731000,
apkName = "org.fdroid.fdroid_1014002.apk",
hash = "3243c24ee95be0fce0830d72e7d2605e3e24f6ccf4ee72a7c8e720fccd7621a1",
hashType = "sha256",
minSdkVersion = 22,
targetSdkVersion = 25,
packageName = "org.fdroid.fdroid",
sig = "9063aaadfff9cfd811a9c72fb5012f28",
signer = "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
size = 8284386,
srcName = "org.fdroid.fdroid_1014002_src.tar.gz",
usesPermission = listOf(
PermissionV1(name = "android.permission.INTERNET"),
PermissionV1(name = "android.permission.ACCESS_NETWORK_STATE"),
PermissionV1(name = "android.permission.ACCESS_WIFI_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_MULTICAST_STATE"),
PermissionV1(name = "android.permission.CHANGE_NETWORK_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_STATE"),
PermissionV1(name = "android.permission.BLUETOOTH"),
PermissionV1(name = "android.permission.BLUETOOTH_ADMIN"),
PermissionV1(name = "android.permission.RECEIVE_BOOT_COMPLETED"),
PermissionV1(name = "android.permission.READ_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_SETTINGS"),
PermissionV1(name = "android.permission.NFC"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = 22),
PermissionV1(name = "android.permission.WAKE_LOCK"),
PermissionV1(name = "android.permission.FOREGROUND_SERVICE"),
),
usesPermission23 = listOf(PermissionV1(name = "android.permission.ACCESS_COARSE_LOCATION")),
versionCode = 1014002,
versionName = "1.14-alpha2",
)
val version2_5 = PackageV1(
added = 1632281729000,
apkName = "org.fdroid.fdroid_1014001.apk",
hash = "7ebfd5eb76f9ec95ba955e549260fe930dc38fb99ed3532f92c93b879aca5610",
hashType = "sha256",
minSdkVersion = 22,
targetSdkVersion = 25,
packageName = "org.fdroid.fdroid",
sig = "9063aaadfff9cfd811a9c72fb5012f28",
signer = "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
size = 8272166,
srcName = "org.fdroid.fdroid_1014001_src.tar.gz",
usesPermission = listOf(
PermissionV1(name = "android.permission.INTERNET"),
PermissionV1(name = "android.permission.ACCESS_NETWORK_STATE"),
PermissionV1(name = "android.permission.ACCESS_WIFI_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_MULTICAST_STATE"),
PermissionV1(name = "android.permission.CHANGE_NETWORK_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_STATE"),
PermissionV1(name = "android.permission.BLUETOOTH"),
PermissionV1(name = "android.permission.BLUETOOTH_ADMIN"),
PermissionV1(name = "android.permission.RECEIVE_BOOT_COMPLETED"),
PermissionV1(name = "android.permission.READ_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_SETTINGS"),
PermissionV1(name = "android.permission.NFC"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = 22),
PermissionV1(name = "android.permission.WAKE_LOCK"),
PermissionV1(name = "android.permission.FOREGROUND_SERVICE"),
),
usesPermission23 = listOf(PermissionV1(name = "android.permission.ACCESS_COARSE_LOCATION")),
versionCode = 1014001,
versionName = "1.14-alpha1",
)
val versions1 = listOf(version1_1, version1_2)
val versions2 = listOf(version2_1, version2_2, version2_3, version2_4, version2_5)
val packages = mapOf(
packageName1 to versions1,
packageName2 to versions2,
)
val index = IndexV1(
repo = repo,
requests = Requests(listOf("installThis"), listOf("uninstallThis")),
apps = apps,
packages = packages,
)
}
internal object TestDataMaxV1 {
val repo = RepoV1(
timestamp = Long.MAX_VALUE,
version = Int.MAX_VALUE,
maxAge = Int.MAX_VALUE,
name = "MaxV1",
icon = "max-v1.png",
address = "https://max-v1.org",
description = "This is a repo with maximum data.",
mirrors = listOf("https://max-v1.com", "https://max-v1.org"),
)
const val packageName1 = TestDataMidV1.packageName1
const val packageName2 = TestDataMidV1.packageName2
const val packageName3 = "Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moo" +
"dahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5Ung" +
"ohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raeph" +
"oowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y"
val categories = listOf("Cat1", "Cat2", "Cat3")
val app2 = TestDataMidV1.app2.copy(
categories = listOf("NoMoreSystem", "OneMore"),
antiFeatures = listOf("AddOne"),
summary = "new summary",
description = "new description",
webSite = "https://fdroid.org",
binaries = "https://fdroid.org/binaries",
name = "F-DroidX",
localized = mapOf(
"ch" to Localized(
description = "new desc",
name = "new name",
summary = "new summary",
tenInchScreenshots = listOf("new screenshots"),
whatsNew = "This is new!"
),
"de" to Localized(
summary = "Der App-Store, der Freiheit und Privatsphäre respektiert",
),
"en-US" to Localized(
description = "F-Droid is an installable catalogue of libre software",
summary = "new summary in en-US",
phoneScreenshots = listOf(
"screenshot-app-details.png",
"screenshot-dark-details.png",
"screenshot-dark-home.png",
"screenshot-search.png",
"screenshot-updates.png",
),
featureGraphic = "featureGraphic_PTun9TO4cMFOeiqbvQSrkdcxNUcOFQCymMIaj9UJOAY=.jpg",
icon = "new icon",
),
),
)
val app3 = AppV1(
packageName = packageName3,
categories = categories,
antiFeatures = listOf("AntiFeature", "NonFreeNet", "NotNice", "VeryBad", "Dont,Show,This"),
summary = "App3 summary",
description = "App3 description",
changelog = "changeLog3",
translation = "translation3",
issueTracker = "tracker3",
sourceCode = "source code3",
binaries = "binaries3",
name = "App3",
authorName = "App3 author",
authorEmail = "email",
authorWebSite = "website",
authorPhone = "phone",
donate = "donate",
liberapayID = "liberapayID",
liberapay = "liberapay",
openCollective = "openCollective",
bitcoin = "bitcoin",
litecoin = "litecoin",
flattrID = "flattrID",
suggestedVersionName = "1.0",
suggestedVersionCode = Long.MIN_VALUE.toString(),
license = "GPLv3",
webSite = "http://min1.test.org",
added = 1234567890,
icon = "icon-max1.png",
lastUpdated = Long.MAX_VALUE,
localized = mapOf(
LOCALE to Localized(
whatsNew = "this is new",
),
"de" to Localized(
whatsNew = "das ist neu",
),
"en" to Localized(
description = "en ",
name = "en ",
icon = "en ",
video = "en ",
phoneScreenshots = listOf("en phoneScreenshots", "en phoneScreenshots2"),
sevenInchScreenshots = listOf("en sevenInchScreenshots",
"en sevenInchScreenshots2"),
tenInchScreenshots = listOf("en tenInchScreenshots", "en tenInchScreenshots2"),
wearScreenshots = listOf("en wearScreenshots", "en wearScreenshots2"),
tvScreenshots = listOf("en tvScreenshots", "en tvScreenshots2"),
featureGraphic = "en ",
promoGraphic = "en ",
tvBanner = "en ",
summary = "en ",
)
),
allowedAPKSigningKeys = listOf("key1, key2"),
)
val apps = listOf(TestDataMidV1.app1, app2, app3)
val version2_2 = TestDataMidV1.version2_2.copy(
usesPermission = emptyList(),
usesPermission23 = emptyList(),
nativeCode = emptyList(),
features = emptyList(),
antiFeatures = emptyList(),
)
val version2_3 = TestDataMidV1.version2_3.copy(
minSdkVersion = 22,
targetSdkVersion = 25,
packageName = "org.fdroid.fdroid",
sig = "9063aaadfff9cfd811a9c72fb5012f28",
signer = "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
size = 8276110,
srcName = "org.fdroid.fdroid_1014003_src.tar.gz",
usesPermission = listOf(
PermissionV1(name = "android.permission.ACCESS_MEDIA"),
PermissionV1(name = "android.permission.CHANGE_WIFI_STATE", maxSdk = 32),
PermissionV1(name = "android.permission.READ_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.NFC"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = 22),
PermissionV1(name = "android.permission.WAKE_LOCK"),
PermissionV1(name = "android.permission.READ_MY_ASS"),
PermissionV1(name = "android.permission.FOREGROUND_SERVICE"),
),
usesPermission23 = listOf(
PermissionV1(name = "android.permission.ACCESS_FINE_LOCATION"),
PermissionV1(name = "android.permission.ACCESS_COARSE_LOCATION", maxSdk = 3),
),
versionCode = 1014003,
versionName = "1.14-alpha3",
)
val version3_1 = PackageV1(
added = 1643250075000,
apkName = "org.fdroid.fdroid_1014050.apk",
hash = "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06",
hashType = "sha256",
minSdkVersion = 22,
maxSdkVersion = Int.MAX_VALUE,
targetSdkVersion = 25,
packageName = "org.fdroid.fdroid",
sig = "9063aaadfff9cfd811a9c72fb5012f28",
signer = "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
size = 8165518,
srcName = "org.fdroid.fdroid_1014050_src.tar.gz",
usesPermission = listOf(
PermissionV1(name = "android.permission.INTERNET"),
PermissionV1(name = "android.permission.ACCESS_NETWORK_STATE"),
PermissionV1(name = "android.permission.ACCESS_WIFI_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_MULTICAST_STATE"),
PermissionV1(name = "android.permission.CHANGE_NETWORK_STATE"),
PermissionV1(name = "android.permission.CHANGE_WIFI_STATE"),
PermissionV1(name = "android.permission.BLUETOOTH"),
PermissionV1(name = "android.permission.BLUETOOTH_ADMIN"),
PermissionV1(name = "android.permission.RECEIVE_BOOT_COMPLETED"),
PermissionV1(name = "android.permission.READ_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_EXTERNAL_STORAGE"),
PermissionV1(name = "android.permission.WRITE_SETTINGS"),
PermissionV1(name = "android.permission.NFC"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = 22),
PermissionV1(name = "android.permission.WAKE_LOCK"),
PermissionV1(name = "android.permission.FOREGROUND_SERVICE")
),
usesPermission23 = listOf(
PermissionV1(name = "android.permission.ACCESS_COARSE_LOCATION"),
PermissionV1(name = "android.permission.USB_PERMISSION", maxSdk = Int.MAX_VALUE),
),
versionCode = 1014050,
versionName = "1.14",
nativeCode = listOf("x86", "x86_64"),
features = listOf("feature", "feature2"),
antiFeatures = listOf("anti-feature", "anti-feature2"),
)
val versions1 = TestDataMidV1.versions1
val versions2 = listOf(
version2_2, version2_3, TestDataMidV1.version2_4, TestDataMidV1.version2_5
)
val versions3 = listOf(version3_1)
val packages = mapOf(
packageName1 to versions1,
packageName2 to versions2,
packageName3 to versions3,
)
val index = IndexV1(
repo = repo,
requests = Requests(listOf("installThis", "installThat"), listOf("uninstallThis")),
apps = apps,
packages = packages,
)
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
package org.fdroid.test
import org.fdroid.index.v2.IndexV2
import kotlin.random.Random
public object TestUtils {
@@ -34,4 +35,26 @@ public object TestUtils {
return if (Random.nextBoolean()) null else this
}
public fun IndexV2.sorted(): IndexV2 = copy(
packages = packages.toSortedMap().mapValues { entry ->
entry.value.copy(
metadata = entry.value.metadata.copy(
name = entry.value.metadata.name?.toSortedMap(),
summary = entry.value.metadata.summary?.toSortedMap(),
description = entry.value.metadata.description?.toSortedMap(),
icon = entry.value.metadata.icon?.toSortedMap(),
),
versions = entry.value.versions.mapValues {
val pv = it.value
pv.copy(
manifest = pv.manifest.copy(
usesPermission = pv.manifest.usesPermission.sortedBy { p -> p.name },
usesPermissionSdk23 = pv.manifest.usesPermissionSdk23.sortedBy { p -> p.name }
)
)
}
)
}
)
}

View File

@@ -0,0 +1,10 @@
{
"repo": {
"timestamp": 23,
"version": 23,
"name": "EmptyV1",
"icon": "empty-v1.png",
"address": "https://empty-v1.org",
"description": "This is a repo with empty data."
}
}

View File

@@ -0,0 +1,15 @@
{
"repo": {
"name": "EmptyV1",
"icon": {
"name": "/icons/empty-v1.png",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 32492
},
"address": "https://empty-v1.org",
"description": {
"en-US": "This is a repo with empty data."
},
"timestamp": 23
}
}

View File

@@ -0,0 +1,600 @@
{
"repo": {
"timestamp": 9223372036854775807,
"version": 2147483647,
"maxage": 2147483647,
"name": "MaxV1",
"icon": "max-v1.png",
"address": "https://max-v1.org",
"description": "This is a repo with maximum data.",
"mirrors": [
"https://max-v1.com",
"https://max-v1.org"
]
},
"requests": {
"install": [
"installThis",
"installThat"
],
"uninstall": [
"uninstallThis"
]
},
"apps": [
{
"categories": [
"Cat1"
],
"antiFeatures": [
"AntiFeature"
],
"summary": "App1 summary",
"description": "App1 description",
"name": "App1",
"authorName": "App1 author",
"license": "GPLv3",
"webSite": "http://min1.test.org",
"added": 1234567890,
"icon": "icon-min1.png",
"packageName": "org.fdroid.min1",
"lastUpdated": 1234567891,
"localized": {
"de": {
"description": "App1 beschreibung",
"name": "app 1 name",
"summary": "App1 Zusammenfassung"
}
}
},
{
"categories": [
"NoMoreSystem",
"OneMore"
],
"antiFeatures": [
"AddOne"
],
"summary": "new summary",
"description": "new description",
"changelog": "https://gitlab.com/fdroid/fdroidclient/raw/HEAD/CHANGELOG.md",
"translation": "https://hosted.weblate.org/projects/f-droid/f-droid",
"issueTracker": "https://gitlab.com/fdroid/fdroidclient/issues",
"sourceCode": "https://gitlab.com/fdroid/fdroidclient",
"binaries": "https://fdroid.org/binaries",
"name": "F-DroidX",
"donate": "https://f-droid.org/donate",
"liberapayID": "27859",
"openCollective": "F-Droid-Euro",
"flattrID": "343053",
"suggestedVersionName": "1.14",
"suggestedVersionCode": "1014050",
"license": "GPL-3.0-or-later",
"webSite": "https://fdroid.org",
"added": 1295222400000,
"icon": "org.fdroid.fdroid.1014050.png",
"packageName": "org.fdroid.fdroid",
"lastUpdated": 1643250075000,
"localized": {
"ch": {
"description": "new desc",
"name": "new name",
"whatsNew": "This is new!",
"tenInchScreenshots": [
"new screenshots"
],
"summary": "new summary"
},
"de": {
"summary": "Der App-Store, der Freiheit und Privatsphäre respektiert"
},
"en-US": {
"description": "F-Droid is an installable catalogue of libre software",
"icon": "new icon",
"phoneScreenshots": [
"screenshot-app-details.png",
"screenshot-dark-details.png",
"screenshot-dark-home.png",
"screenshot-search.png",
"screenshot-updates.png"
],
"featureGraphic": "featureGraphic_PTun9TO4cMFOeiqbvQSrkdcxNUcOFQCymMIaj9UJOAY=.jpg",
"summary": "new summary in en-US"
}
}
},
{
"categories": [
"Cat1",
"Cat2",
"Cat3"
],
"antiFeatures": [
"AntiFeature",
"NonFreeNet",
"NotNice",
"VeryBad",
"Dont,Show,This"
],
"summary": "App3 summary",
"description": "App3 description",
"changelog": "changeLog3",
"translation": "translation3",
"issueTracker": "tracker3",
"sourceCode": "source code3",
"binaries": "binaries3",
"name": "App3",
"authorName": "App3 author",
"authorEmail": "email",
"authorWebSite": "website",
"authorPhone": "phone",
"donate": "donate",
"liberapayID": "liberapayID",
"liberapay": "liberapay",
"openCollective": "openCollective",
"bitcoin": "bitcoin",
"litecoin": "litecoin",
"flattrID": "flattrID",
"suggestedVersionName": "1.0",
"suggestedVersionCode": "-9223372036854775808",
"license": "GPLv3",
"webSite": "http://min1.test.org",
"added": 1234567890,
"icon": "icon-max1.png",
"packageName": "Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y",
"lastUpdated": 9223372036854775807,
"localized": {
"en-US": {
"whatsNew": "this is new"
},
"de": {
"whatsNew": "das ist neu"
},
"en": {
"description": "en ",
"name": "en ",
"icon": "en ",
"video": "en ",
"phoneScreenshots": [
"en phoneScreenshots",
"en phoneScreenshots2"
],
"sevenInchScreenshots": [
"en sevenInchScreenshots",
"en sevenInchScreenshots2"
],
"tenInchScreenshots": [
"en tenInchScreenshots",
"en tenInchScreenshots2"
],
"wearScreenshots": [
"en wearScreenshots",
"en wearScreenshots2"
],
"tvScreenshots": [
"en tvScreenshots",
"en tvScreenshots2"
],
"featureGraphic": "en ",
"promoGraphic": "en ",
"tvBanner": "en ",
"summary": "en "
}
},
"allowedAPKSigningKeys": [
"key1, key2"
]
}
],
"packages": {
"org.fdroid.min1": [
{
"added": 2342,
"apkName": "org.fdroid.min1_23_2.apk",
"hash": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"hashType": "sha256",
"packageName": "org.fdroid.min1",
"size": 1338,
"srcname": "org.fdroid.min1_23_2.zip",
"uses-permission": [
[
"perm",
null
]
],
"versionCode": 1,
"versionName": "1",
"nativecode": [
"x86"
],
"features": [
"feature"
],
"antiFeatures": [
"anti-feature"
]
},
{
"apkName": "org.fdroid.min1_42.apk",
"hash": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"hashType": "sha256",
"minSdkVersion": 21,
"maxSdkVersion": 4568,
"targetSdkVersion": 32,
"packageName": "org.fdroid.min1",
"sig": "old",
"signer": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337,
"srcname": "org.fdroid.min1_42.zip",
"versionCode": 24,
"versionName": "24"
}
],
"org.fdroid.fdroid": [
{
"added": 1642785071000,
"apkName": "org.fdroid.fdroid_1014005.apk",
"hash": "b4282febf5558d43c7c51a00478961f6df1b6d59e0a6674974cdacb792683e5d",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8382606,
"srcname": "org.fdroid.fdroid_1014005_src.tar.gz",
"versionCode": 1014005,
"versionName": "1.14-alpha5",
"nativecode": [
],
"features": [
],
"antiFeatures": [
]
},
{
"added": 1635169849000,
"apkName": "org.fdroid.fdroid_1014003.apk",
"hash": "c062a9642fde08aacabbfa4cab1ab5773c83f4e6b81551ffd92027d2b20f37d3",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8276110,
"srcname": "org.fdroid.fdroid_1014003_src.tar.gz",
"uses-permission": [
[
"android.permission.ACCESS_MEDIA",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
32
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.READ_MY_ASS",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_FINE_LOCATION",
null
],
[
"android.permission.ACCESS_COARSE_LOCATION",
3
]
],
"versionCode": 1014003,
"versionName": "1.14-alpha3"
},
{
"added": 1632281731000,
"apkName": "org.fdroid.fdroid_1014002.apk",
"hash": "3243c24ee95be0fce0830d72e7d2605e3e24f6ccf4ee72a7c8e720fccd7621a1",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8284386,
"srcname": "org.fdroid.fdroid_1014002_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
]
],
"versionCode": 1014002,
"versionName": "1.14-alpha2"
},
{
"added": 1632281729000,
"apkName": "org.fdroid.fdroid_1014001.apk",
"hash": "7ebfd5eb76f9ec95ba955e549260fe930dc38fb99ed3532f92c93b879aca5610",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8272166,
"srcname": "org.fdroid.fdroid_1014001_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
]
],
"versionCode": 1014001,
"versionName": "1.14-alpha1"
}
],
"Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y": [
{
"added": 1643250075000,
"apkName": "org.fdroid.fdroid_1014050.apk",
"hash": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06",
"hashType": "sha256",
"minSdkVersion": 22,
"maxSdkVersion": 2147483647,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8165518,
"srcname": "org.fdroid.fdroid_1014050_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
],
[
"android.permission.USB_PERMISSION",
2147483647
]
],
"versionCode": 1014050,
"versionName": "1.14",
"nativecode": [
"x86",
"x86_64"
],
"features": [
"feature",
"feature2"
],
"antiFeatures": [
"anti-feature",
"anti-feature2"
]
}
]
}
}

View File

@@ -0,0 +1,853 @@
{
"repo": {
"name": "MaxV1",
"icon": {
"name": "/icons/max-v1.png",
"sha256": "14758e480ae76297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 9223372036854775807
},
"address": "https://max-v1.org",
"webBaseUrl": "https://www.max-v1.org",
"description": {
"en-US": "This is a repo with maximum data.",
"de": "Dies ist ein Repo mit maximaler Datendichte."
},
"mirrors": [
{
"url": "https://max-v1.com",
"location": "us"
},
{
"url": "https://max-v1.org",
"location": "nl"
}
],
"timestamp": 9223372036854775807,
"antiFeatures": {
"VeryBad": {
"name": {
}
},
"Dont,Show,This": {
"name": {
}
},
"NotNice": {
"name": {
}
},
"AntiFeature": {
"icon": {
"name": "/icons/antifeature.png",
"sha256": "24758e480ae66297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 254916
},
"name": {
"en-US": "AntiFeature"
},
"description": {
"en-US": "A bad anti-feature, we can't show to users."
}
},
"NonFreeNet": {
"name": {
"en-US": "NonFreeNet"
}
},
"AddOne": {
"name": {
"en-US": "AddOne anti feature"
},
"description": {
"en-US": "A bad anti-feature, that was added in an update."
}
}
},
"categories": {
"Cat3": {
"icon": {
"name": "/icons/cat3.png",
"sha256": "54758e480ae76297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 9223372036854775807
},
"name": {
"en-US": "Cat3"
},
"description": {
"en-US": "Cat3"
}
},
"Cat2": {
"icon": {
"name": "/icons/cat2.png",
"sha256": "54758e480ae76297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 9223372036854775807
},
"name": {
"en-US": "Cat3"
},
"description": {
"en-US": "Cat3"
}
},
"Cat1": {
"icon": {
"name": "/icons/cat1.png",
"sha256": "54758e480ae76297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 9223372036854775807
},
"name": {
"en-US": "Cat1"
},
"description": {
"en-US": "Cat1"
}
},
"NoMoreSystem": {
"name": {
}
},
"OneMore": {
"name": {
}
}
},
"releaseChannels": {
"Alpha": {
"name": {
"de": "channel name alpha"
},
"description": {
"de-DE": "channel desc alpha"
}
},
"Beta": {
"name": {
"en-US": "channel name"
},
"description": {
"en-US": "channel desc"
}
}
}
},
"packages": {
"org.fdroid.min1": {
"metadata": {
"name": {
"en-US": "App1",
"de": "app 1 name"
},
"summary": {
"en-US": "App1 summary",
"de": "App1 Zusammenfassung"
},
"description": {
"en-US": "App1 description",
"de": "App1 beschreibung"
},
"added": 1234567890,
"lastUpdated": 1234567891,
"webSite": "http://min1.test.org",
"license": "GPLv3",
"categories": [
"Cat1"
],
"author": {
"name": "App1 author"
},
"icon": {
"en-US": {
"name": "/icons/icon-min1.png",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337
}
}
},
"versions": {
"824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf": {
"added": 0,
"file": {
"name": "/org.fdroid.min1_42.apk",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337
},
"src": {
"name": "/org.fdroid.min1_42.zip",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1338
},
"manifest": {
"versionName": "24",
"versionCode": 24,
"usesSdk": {
"minSdkVersion": 21,
"targetSdkVersion": 32
},
"maxSdkVersion": 4568,
"signer": {
"sha256": [
"824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf"
]
}
},
"releaseChannels": [
"Beta"
],
"antiFeatures": {
"AntiFeature": {
"en-US": "reason"
}
}
}
}
},
"org.fdroid.fdroid": {
"metadata": {
"name": {
"en-US": "F-DroidX",
"ch": "new name"
},
"summary": {
"en-US": "new summary in en-US",
"ch": "new summary",
"de": "Der App-Store, der Freiheit und Privatsphäre respektiert"
},
"description": {
"en-US": "F-Droid is an installable catalogue of libre software",
"ch": "new desc"
},
"added": 1295222400000,
"lastUpdated": 1643250075000,
"webSite": "https://fdroid.org",
"changelog": "https://gitlab.com/fdroid/fdroidclient/raw/HEAD/CHANGELOG.md",
"license": "GPL-3.0-or-later",
"sourceCode": "https://gitlab.com/fdroid/fdroidclient",
"issueTracker": "https://gitlab.com/fdroid/fdroidclient/issues",
"translation": "https://hosted.weblate.org/projects/f-droid/f-droid",
"preferredSigner": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"categories": [
"NoMoreSystem",
"OneMore"
],
"donation": {
"url": "https://f-droid.org/donate",
"liberapayID": "27859",
"openCollective": "F-Droid-Euro",
"flattrID": "343053"
},
"icon": {
"en-US": {
"name": "/org.fdroid.fdroid/en-US/new icon",
"sha256": "324a109b2352138c3699760e1683385d1ed50ce526fc7982f8d65757743374ba",
"size": 2233
}
},
"featureGraphic": {
"en-US": {
"name": "/org.fdroid.fdroid/en-US/featureGraphic_PTun9TO4cMFOeiqbvQSrkdcxNUcOFQCymMIaj9UJOAY=.jpg",
"sha256": "424a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 4237
}
},
"screenshots": {
"phone": {
"en-US": [
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-app-details.png",
"sha256": "424a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 4237
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-dark-details.png",
"sha256": "424a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 44287
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-dark-home.png",
"sha256": "424a109b2352138c3699760e1673385d0ed50ce526fc7982f8d65757743374bf",
"size": 4587
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-search.png",
"sha256": "424a109b2352138c3694760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 2857
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-updates.png",
"sha256": "424a109b2352138c3699750e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 485286
}
]
},
"tenInch": {
"ch": [
{
"name": "/org.fdroid.fdroid/ch/tenInchScreenshots/new screenshots",
"sha256": "54758e380ae76297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": -9223372036854775808
}
]
}
}
},
"versions": {
"b4282febf5558d43c7c51a00478961f6df1b6d59e0a6674974cdacb792683e5d": {
"added": 1642785071000,
"file": {
"name": "/org.fdroid.fdroid_1014005.apk",
"sha256": "b4282febf5558d43c7c51a00478961f6df1b6d59e0a6674974cdacb792683e5d",
"size": 8382606
},
"src": {
"name": "/org.fdroid.fdroid_1014005_src.tar.gz",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d07",
"size": 8165519
},
"manifest": {
"versionName": "1.14-alpha5",
"versionCode": 1014005,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
}
},
"antiFeatures": {
"AddOne": {
"en-US": "was added this update"
}
},
"whatsNew": {
"ch": "This is new!"
}
},
"c062a9642fde08aacabbfa4cab1ab5773c83f4e6b81551ffd92027d2b20f37d3": {
"added": 1635169849000,
"file": {
"name": "/org.fdroid.fdroid_1014003.apk",
"sha256": "c062a9642fde08aacabbfa4cab1ab5773c83f4e6b81551ffd92027d2b20f37d3",
"size": 8276110
},
"src": {
"name": "/org.fdroid.fdroid_1014003_src.tar.gz",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cb067d510ac6f3e0d07",
"size": 8165519
},
"manifest": {
"versionName": "1.14-alpha3",
"versionCode": 1014003,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.ACCESS_MEDIA"
},
{
"name": "android.permission.CHANGE_WIFI_STATE",
"maxSdkVersion": 32
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.READ_MY_ASS"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_FINE_LOCATION"
},
{
"name": "android.permission.ACCESS_COARSE_LOCATION",
"maxSdkVersion": 3
}
]
},
"antiFeatures": {
"AddOne": {
"en-US": "was added this update"
}
}
},
"3243c24ee95be0fce0830d72e7d2605e3e24f6ccf4ee72a7c8e720fccd7621a1": {
"added": 1632281731000,
"file": {
"name": "/org.fdroid.fdroid_1014002.apk",
"sha256": "3243c24ee95be0fce0830d72e7d2605e3e24f6ccf4ee72a7c8e720fccd7621a1",
"size": 8284386
},
"src": {
"name": "/org.fdroid.fdroid_1014002_src.tar.gz",
"sha256": "7c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cb067d510ac6f3e0d07",
"size": 7165519
},
"manifest": {
"versionName": "1.14-alpha2",
"versionCode": 1014002,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
}
]
},
"antiFeatures": {
"AddOne": {
}
}
},
"7ebfd5eb76f9ec95ba955e549260fe930dc38fb99ed3532f92c93b879aca5610": {
"added": 1632281729000,
"file": {
"name": "/org.fdroid.fdroid_1014001.apk",
"sha256": "7ebfd5eb76f9ec95ba955e549260fe930dc38fb99ed3532f92c93b879aca5610",
"size": 8272166
},
"src": {
"name": "/org.fdroid.fdroid_1014001_src.tar.gz",
"sha256": "6c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cb067d510ac6f3e0d07",
"size": 6165519
},
"manifest": {
"versionName": "1.14-alpha1",
"versionCode": 1014001,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
}
]
},
"antiFeatures": {
"AddOne": {
"en-US": "was added this update"
}
}
}
}
},
"Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y": {
"metadata": {
"name": {
"en-US": "App3",
"en": "en "
},
"summary": {
"en-US": "App3 summary",
"en": "en "
},
"description": {
"en-US": "App3 description",
"en": "en "
},
"added": 1234567890,
"lastUpdated": 9223372036854775807,
"webSite": "http://min1.test.org",
"changelog": "changeLog3",
"license": "GPLv3",
"sourceCode": "source code3",
"issueTracker": "tracker3",
"translation": "translation3",
"preferredSigner": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"categories": [
"Cat1",
"Cat2",
"Cat3"
],
"author": {
"name": "App3 author",
"email": "email",
"website": "website",
"phone": "phone"
},
"donation": {
"url": "donate",
"liberapayID": "liberapayID",
"liberapay": "liberapay",
"openCollective": "openCollective",
"bitcoin": "bitcoin",
"litecoin": "litecoin",
"flattrID": "flattrID"
},
"icon": {
"en": {
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/en ",
"sha256": "32758e380aeg6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 2253245
}
},
"featureGraphic": {
"en": {
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/en ",
"sha256": "54758e380ae762f7c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 32453245
}
},
"promoGraphic": {
"en": {
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/en ",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 4523325
}
},
"tvBanner": {
"en": {
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/en ",
"sha256": "54758e380aeh6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 32453245
}
},
"video": {
"en": "en "
},
"screenshots": {
"phone": {
"en": [
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/phoneScreenshots/en phoneScreenshots",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
},
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/phoneScreenshots/en phoneScreenshots2",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
}
]
},
"sevenInch": {
"en": [
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/sevenInchScreenshots/en sevenInchScreenshots",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
},
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/sevenInchScreenshots/en sevenInchScreenshots2",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
}
]
},
"tenInch": {
"en": [
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/tenInchScreenshots/en tenInchScreenshots",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
},
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/tenInchScreenshots/en tenInchScreenshots2",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
}
]
},
"wear": {
"en": [
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/wearScreenshots/en wearScreenshots",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
},
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/wearScreenshots/en wearScreenshots2",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
}
]
},
"tv": {
"en": [
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/tvScreenshots/en tvScreenshots",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
},
{
"name": "/Haoheiseeshai2que2Che0ooSa6aikeemoo2ap9Aequoh4ju5chooYuPhiev8moodahlonu2oht5Eikahvushapeum5aefo6xig4aghahyaaNuezoo4eexee1Goo5UngohGha6quaeghe8uCh9iex9Oowa9aiyohzoo2ij5miifiegaeth8nie9jae6raephoowishoor1Ien5vahGhahm7eidaiy2AeCaej9iexahyooshu2ic9tea1ool8tu4Y/en/tvScreenshots/en tvScreenshots2",
"sha256": "54758e380aee6297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
}
]
}
}
},
"versions": {
"8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06": {
"added": 1643250075000,
"file": {
"name": "/org.fdroid.fdroid_1014050.apk",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06",
"size": 8165518
},
"src": {
"name": "/org.fdroid.fdroid_1014050_src.tar.gz",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06",
"size": 8165518
},
"manifest": {
"versionName": "1.14",
"versionCode": 1014050,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"maxSdkVersion": 2147483647,
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"33238d512c1e3eb2d6569f4a3bfbf5523418b22e0a3ed1552770abb9a9c9ccvb"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 2147483647
}
],
"nativecode": [
"x86",
"x86_64"
],
"features": [
{
"name": "feature"
},
{
"name": "feature2"
}
]
},
"releaseChannels": [
"Beta",
"Alpha"
],
"antiFeatures": {
"AntiFeature": {
},
"NonFreeNet": {
},
"NotNice": {
},
"VeryBad": {
},
"Dont,Show,This": {
},
"anti-feature": {
"en-US": "bla",
"de": "blubb"
},
"anti-feature2": {
"de": "blabla"
}
},
"whatsNew": {
"en-US": "this is new",
"de": "das ist neu"
}
}
}
}
}
}

View File

@@ -0,0 +1,629 @@
{
"repo": {
"timestamp": 1337,
"version": 1,
"maxage": 23,
"name": "MidV1",
"icon": "mid-v1.png",
"address": "https://mid-v1.org",
"description": "This is a repo with medium data.",
"mirrors": [
"https://mid-v1.com"
]
},
"requests": {
"install": [
"installThis"
],
"uninstall": [
"uninstallThis"
]
},
"apps": [
{
"categories": [
"Cat1"
],
"antiFeatures": [
"AntiFeature"
],
"summary": "App1 summary",
"description": "App1 description",
"name": "App1",
"authorName": "App1 author",
"license": "GPLv3",
"webSite": "http://min1.test.org",
"added": 1234567890,
"icon": "icon-min1.png",
"packageName": "org.fdroid.min1",
"lastUpdated": 1234567891,
"localized": {
"de": {
"description": "App1 beschreibung",
"name": "app 1 name",
"summary": "App1 Zusammenfassung"
}
}
},
{
"categories": [
"System"
],
"changelog": "https://gitlab.com/fdroid/fdroidclient/raw/HEAD/CHANGELOG.md",
"translation": "https://hosted.weblate.org/projects/f-droid/f-droid",
"issueTracker": "https://gitlab.com/fdroid/fdroidclient/issues",
"sourceCode": "https://gitlab.com/fdroid/fdroidclient",
"donate": "https://f-droid.org/donate",
"liberapayID": "27859",
"openCollective": "F-Droid-Euro",
"flattrID": "343053",
"suggestedVersionName": "1.14",
"suggestedVersionCode": "1014050",
"license": "GPL-3.0-or-later",
"webSite": "https://f-droid.org",
"added": 1295222400000,
"icon": "org.fdroid.fdroid.1014050.png",
"packageName": "org.fdroid.fdroid",
"lastUpdated": 1643250075000,
"localized": {
"af": {
"description": "F-Droid is 'n installeerbare katalogus van gratis sagteware",
"name": "-درويد",
"summary": "متجر التطبيقات الذي يحترم الحرية والخصوصية)"
},
"be": {
"name": "F-Droid",
"summary": "Крама праграм, якая паважае свабоду і прыватнасць"
},
"bg": {
"summary": "Магазинът за приложения, който уважава независимостта и поверителността"
},
"bn": {
"name": "এফ-ড্রয়েড",
"summary": "যে অ্যাপ স্টোর স্বাধীনতা ও গোপনীয়তা সম্মান করে"
},
"bo": {
"description": "ཨེཕ་རོཌ་ནི་ཨེན་ཀྲོཌ་བབ་སྟེགས་ཀྱི་ཆེད་དུ་FOSS",
"summary": "རང་དབང་དང་གསང་དོན་ལ་གུས་བརྩི་ཞུས་མཁན་གྱི་མཉེན་ཆས་ཉར་ཚགས་ཁང་།"
},
"ca": {
"description": "F-Droid és un catàleg instal·lable d'aplicacions de software lliure",
"name": "F-Droid",
"summary": "La botiga d'aplicacions que respecta la llibertat i la privacitat"
},
"cs": {
"description": "F-Droid je instalovatelný katalog softwarových libre",
"name": "F-Droid",
"summary": "Zdroj aplikací který respektuje vaši svobodu a soukromí"
},
"cy": {
"description": "Mae F-Droid yn gatalog y gellir ei osod o apiau meddalwedd rhyddar gyfer Android.",
"name": "F-Droid",
"summary": "Yr ystorfa apiau sy'n parchu rhyddid a phreifatrwydd"
},
"de": {
"description": "F-Droid ist ein installierbarer Katalog mit Libre SoftwareAndroid-Apps.",
"summary": "Der App-Store, der Freiheit und Privatsphäre respektiert"
},
"el": {
"description": "Το F-Droid είναι ένας κατάλογος εφαρμογών ελεύθερου λογισμικού",
"name": "F-Droid",
"summary": "Το κατάστημα εφαρμογών που σέβεται την ελευθερία και την ιδιωτικότητα"
},
"en-US": {
"description": "F-Droid is an installable catalogue of libre software",
"name": "F-Droid",
"whatsNew": "* Overhaul Share menu to use built-in options like Nearby",
"phoneScreenshots": [
"screenshot-app-details.png",
"screenshot-dark-details.png",
"screenshot-dark-home.png",
"screenshot-dark-knownvuln.png",
"screenshot-knownvuln.png",
"screenshot-search.png",
"screenshot-updates.png"
],
"featureGraphic": "featureGraphic_PTun9TO4cMFOeiqbvQSrkdcxNUcOFQCymMIaj9UJOAY=.jpg",
"summary": "The app store that respects freedom and privacy"
},
"eo": {
"description": "F-Droid estas instalebla katalogo de liberaj aplikaĵoj por Android.",
"name": "F-Droid",
"whatsNew": "• rekonstruita menuo “Kunhavigi” por uzi enkonstruitajn eblojn, ekz.",
"summary": "Aplikaĵa vendejo respektanta liberecon kaj privatecon"
}
}
}
],
"packages": {
"org.fdroid.min1": [
{
"added": 2342,
"apkName": "org.fdroid.min1_23_2.apk",
"hash": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"hashType": "sha256",
"packageName": "org.fdroid.min1",
"size": 1338,
"srcname": "org.fdroid.min1_23_2.zip",
"uses-permission": [
[
"perm",
null
]
],
"versionCode": 1,
"versionName": "1",
"nativecode": [
"x86"
],
"features": [
"feature"
],
"antiFeatures": [
"anti-feature"
]
},
{
"apkName": "org.fdroid.min1_42.apk",
"hash": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"hashType": "sha256",
"minSdkVersion": 21,
"maxSdkVersion": 4568,
"targetSdkVersion": 32,
"packageName": "org.fdroid.min1",
"sig": "old",
"signer": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337,
"srcname": "org.fdroid.min1_42.zip",
"versionCode": 24,
"versionName": "24"
}
],
"org.fdroid.fdroid": [
{
"added": 1643250075000,
"apkName": "org.fdroid.fdroid_1014050.apk",
"hash": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8165518,
"srcname": "org.fdroid.fdroid_1014050_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
]
],
"versionCode": 1014050,
"versionName": "1.14"
},
{
"added": 1642785071000,
"apkName": "org.fdroid.fdroid_1014005.apk",
"hash": "b4282febf5558d43c7c51a00478961f6df1b6d59e0a6674974cdacb792683e5d",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8382606,
"srcname": "org.fdroid.fdroid_1014005_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
]
],
"versionCode": 1014005,
"versionName": "1.14-alpha5",
"nativecode": [
"fakeNativeCode"
],
"features": [
"fake feature"
],
"antiFeatures": [
"FakeAntiFeature"
]
},
{
"added": 1635169849000,
"apkName": "org.fdroid.fdroid_1014003.apk",
"hash": "c062a9642fde08aacabbfa4cab1ab5773c83f4e6b81551ffd92027d2b20f37d3",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8276110,
"srcname": "org.fdroid.fdroid_1014003_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
]
],
"versionCode": 1014003,
"versionName": "1.14-alpha3"
},
{
"added": 1632281731000,
"apkName": "org.fdroid.fdroid_1014002.apk",
"hash": "3243c24ee95be0fce0830d72e7d2605e3e24f6ccf4ee72a7c8e720fccd7621a1",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8284386,
"srcname": "org.fdroid.fdroid_1014002_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
]
],
"versionCode": 1014002,
"versionName": "1.14-alpha2"
},
{
"added": 1632281729000,
"apkName": "org.fdroid.fdroid_1014001.apk",
"hash": "7ebfd5eb76f9ec95ba955e549260fe930dc38fb99ed3532f92c93b879aca5610",
"hashType": "sha256",
"minSdkVersion": 22,
"targetSdkVersion": 25,
"packageName": "org.fdroid.fdroid",
"sig": "9063aaadfff9cfd811a9c72fb5012f28",
"signer": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"size": 8272166,
"srcname": "org.fdroid.fdroid_1014001_src.tar.gz",
"uses-permission": [
[
"android.permission.INTERNET",
null
],
[
"android.permission.ACCESS_NETWORK_STATE",
null
],
[
"android.permission.ACCESS_WIFI_STATE",
null
],
[
"android.permission.CHANGE_WIFI_MULTICAST_STATE",
null
],
[
"android.permission.CHANGE_NETWORK_STATE",
null
],
[
"android.permission.CHANGE_WIFI_STATE",
null
],
[
"android.permission.BLUETOOTH",
null
],
[
"android.permission.BLUETOOTH_ADMIN",
null
],
[
"android.permission.RECEIVE_BOOT_COMPLETED",
null
],
[
"android.permission.READ_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_EXTERNAL_STORAGE",
null
],
[
"android.permission.WRITE_SETTINGS",
null
],
[
"android.permission.NFC",
null
],
[
"android.permission.USB_PERMISSION",
22
],
[
"android.permission.WAKE_LOCK",
null
],
[
"android.permission.FOREGROUND_SERVICE",
null
]
],
"uses-permission-sdk-23": [
[
"android.permission.ACCESS_COARSE_LOCATION",
null
]
],
"versionCode": 1014001,
"versionName": "1.14-alpha1"
}
]
}
}

View File

@@ -0,0 +1,660 @@
{
"repo": {
"name": "MidV1",
"icon": {
"name": "/icons/mid-v1.png",
"sha256": "74758e480ae76297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 234232352235
},
"address": "https://mid-v1.org",
"description": {
"en-US": "This is a repo with medium data.",
"de": "Dies ist ein Repo mit mittlerer Datendichte."
},
"mirrors": [
{
"url": "https://mid-v1.com"
}
],
"timestamp": 1337,
"antiFeatures": {
"AntiFeature": {
"name": {
"en-US": "AntiFeature"
},
"description": {
"en-US": "A bad anti-feature, we can't show to users."
}
}
},
"categories": {
"Cat1": {
"icon": {
"name": "/icons/cat2.png",
"sha256": "54758e480ae76297c7947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 9223372036854775807
},
"name": {
"en-US": "Cat1"
}
},
"System": {
"name": {
}
}
}
},
"packages": {
"org.fdroid.min1": {
"metadata": {
"name": {
"en-US": "App1",
"de" : "app 1 name"
},
"summary": {
"en-US": "App1 summary",
"de": "App1 Zusammenfassung"
},
"description": {
"en-US": "App1 description",
"de": "App1 beschreibung"
},
"added": 1234567890,
"lastUpdated": 1234567891,
"webSite": "http://min1.test.org",
"license": "GPLv3",
"categories": [
"Cat1"
],
"author": {
"name": "App1 author"
},
"icon": {
"en-US": {
"name": "/icons/icon-min1.png",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337
}
}
},
"versions": {
"824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf": {
"added": 0,
"file": {
"name": "/org.fdroid.min1_42.apk",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337
},
"src": {
"name": "/org.fdroid.min1_42.zip",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1338
},
"manifest": {
"versionName": "24",
"versionCode": 24,
"usesSdk": {
"minSdkVersion": 21,
"targetSdkVersion": 32
},
"maxSdkVersion": 4568,
"signer": {
"sha256": [
"824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf"
]
}
},
"releaseChannels": [
"Beta"
],
"antiFeatures": {
"AntiFeature": {
"en-US": "reason"
}
}
}
}
},
"org.fdroid.fdroid": {
"metadata": {
"name": {
"af": "-درويد",
"be": "F-Droid",
"bn": "এফ-ড্রয়েড",
"ca": "F-Droid",
"cs": "F-Droid",
"cy": "F-Droid",
"el": "F-Droid",
"en-US": "F-Droid",
"eo": "F-Droid"
},
"summary": {
"af": "متجر التطبيقات الذي يحترم الحرية والخصوصية)",
"be": "Крама праграм, якая паважае свабоду і прыватнасць",
"bg": "Магазинът за приложения, който уважава независимостта и поверителността",
"bn": "যে অ্যাপ স্টোর স্বাধীনতা ও গোপনীয়তা সম্মান করে",
"bo": "རང་དབང་དང་གསང་དོན་ལ་གུས་བརྩི་ཞུས་མཁན་གྱི་མཉེན་ཆས་ཉར་ཚགས་ཁང་།",
"ca": "La botiga d'aplicacions que respecta la llibertat i la privacitat",
"cs": "Zdroj aplikací který respektuje vaši svobodu a soukromí",
"cy": "Yr ystorfa apiau sy'n parchu rhyddid a phreifatrwydd",
"de": "Der App-Store, der Freiheit und Privatsphäre respektiert",
"el": "Το κατάστημα εφαρμογών που σέβεται την ελευθερία και την ιδιωτικότητα",
"en-US": "The app store that respects freedom and privacy",
"eo": "Aplikaĵa vendejo respektanta liberecon kaj privatecon"
},
"description": {
"af": "F-Droid is 'n installeerbare katalogus van gratis sagteware",
"bo": "ཨེཕ་རོཌ་ནི་ཨེན་ཀྲོཌ་བབ་སྟེགས་ཀྱི་ཆེད་དུ་FOSS",
"ca": "F-Droid és un catàleg instal·lable d'aplicacions de software lliure",
"cs": "F-Droid je instalovatelný katalog softwarových libre",
"cy": "Mae F-Droid yn gatalog y gellir ei osod o apiau meddalwedd rhyddar gyfer Android.",
"de": "F-Droid ist ein installierbarer Katalog mit Libre SoftwareAndroid-Apps.",
"el": "Το F-Droid είναι ένας κατάλογος εφαρμογών ελεύθερου λογισμικού",
"en-US": "F-Droid is an installable catalogue of libre software",
"eo": "F-Droid estas instalebla katalogo de liberaj aplikaĵoj por Android."
},
"added": 1295222400000,
"lastUpdated": 1643250075000,
"webSite": "https://f-droid.org",
"changelog": "https://gitlab.com/fdroid/fdroidclient/raw/HEAD/CHANGELOG.md",
"license": "GPL-3.0-or-later",
"sourceCode": "https://gitlab.com/fdroid/fdroidclient",
"issueTracker": "https://gitlab.com/fdroid/fdroidclient/issues",
"translation": "https://hosted.weblate.org/projects/f-droid/f-droid",
"preferredSigner": "43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab",
"categories": [
"System"
],
"donation": {
"url": "https://f-droid.org/donate",
"liberapayID": "27859",
"openCollective": "F-Droid-Euro",
"flattrID": "343053"
},
"icon": {
"en-US": {
"name": "/icons/org.fdroid.fdroid.1014050.png",
"sha256": "224a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1237
}
},
"featureGraphic": {
"en-US": {
"name": "/org.fdroid.fdroid/en-US/featureGraphic_PTun9TO4cMFOeiqbvQSrkdcxNUcOFQCymMIaj9UJOAY=.jpg",
"sha256": "424a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 4237
}
},
"screenshots": {
"phone": {
"en-US": [
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-app-details.png",
"sha256": "424a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 4237
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-dark-details.png",
"sha256": "424a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 44287
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-dark-home.png",
"sha256": "424a109b2352138c3699760e1673385d0ed50ce526fc7982f8d65757743374bf",
"size": 4587
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-dark-knownvuln.png",
"sha256": "424a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 445837
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-knownvuln.png",
"sha256": "424a109b2352138c4599760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 4287
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-search.png",
"sha256": "424a109b2352138c3694760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 2857
},
{
"name": "/org.fdroid.fdroid/en-US/phoneScreenshots/screenshot-updates.png",
"sha256": "424a109b2352138c3699750e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 485287
}
]
}
}
},
"versions": {
"8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06": {
"added": 1643250075000,
"file": {
"name": "/org.fdroid.fdroid_1014050.apk",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d06",
"size": 8165518
},
"src": {
"name": "/org.fdroid.fdroid_1014050_src.tar.gz",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d07",
"size": 8165519
},
"manifest": {
"versionName": "1.14",
"versionCode": 1014050,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
}
]
},
"whatsNew": {
"en-US": "* Overhaul Share menu to use built-in options like Nearby",
"eo": "• rekonstruita menuo “Kunhavigi” por uzi enkonstruitajn eblojn, ekz."
}
},
"b4282febf5558d43c7c51a00478961f6df1b6d59e0a6674974cdacb792683e5d": {
"added": 1642785071000,
"file": {
"name": "/org.fdroid.fdroid_1014005.apk",
"sha256": "b4282febf5558d43c7c51a00478961f6df1b6d59e0a6674974cdacb792683e5d",
"size": 8382606
},
"src": {
"name": "/org.fdroid.fdroid_1014005_src.tar.gz",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cc067d510ac6f3e0d07",
"size": 8165519
},
"manifest": {
"versionName": "1.14-alpha5",
"versionCode": 1014005,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
}
],
"nativecode": [
"fakeNativeCode"
],
"features": [
{
"name": "fake feature"
}
]
},
"antiFeatures": {
"FakeAntiFeature": {
}
}
},
"c062a9642fde08aacabbfa4cab1ab5773c83f4e6b81551ffd92027d2b20f37d3": {
"added": 1635169849000,
"file": {
"name": "/org.fdroid.fdroid_1014003.apk",
"sha256": "c062a9642fde08aacabbfa4cab1ab5773c83f4e6b81551ffd92027d2b20f37d3",
"size": 8276110
},
"src": {
"name": "/org.fdroid.fdroid_1014003_src.tar.gz",
"sha256": "8c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cb067d510ac6f3e0d07",
"size": 8165519
},
"manifest": {
"versionName": "1.14-alpha3",
"versionCode": 1014003,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
}
]
}
},
"3243c24ee95be0fce0830d72e7d2605e3e24f6ccf4ee72a7c8e720fccd7621a1": {
"added": 1632281731000,
"file": {
"name": "/org.fdroid.fdroid_1014002.apk",
"sha256": "3243c24ee95be0fce0830d72e7d2605e3e24f6ccf4ee72a7c8e720fccd7621a1",
"size": 8284386
},
"src": {
"name": "/org.fdroid.fdroid_1014002_src.tar.gz",
"sha256": "7c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cb067d510ac6f3e0d07",
"size": 7165519
},
"manifest": {
"versionName": "1.14-alpha2",
"versionCode": 1014002,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
}
]
}
},
"7ebfd5eb76f9ec95ba955e549260fe930dc38fb99ed3532f92c93b879aca5610": {
"added": 1632281729000,
"file": {
"name": "/org.fdroid.fdroid_1014001.apk",
"sha256": "7ebfd5eb76f9ec95ba955e549260fe930dc38fb99ed3532f92c93b879aca5610",
"size": 8272166
},
"src": {
"name": "/org.fdroid.fdroid_1014001_src.tar.gz",
"sha256": "6c89ce2f42f4a89af8ca6e1ea220f9dfdee220724d8a9cb067d510ac6f3e0d07",
"size": 6165519
},
"manifest": {
"versionName": "1.14-alpha1",
"versionCode": 1014001,
"usesSdk": {
"minSdkVersion": 22,
"targetSdkVersion": 25
},
"signer": {
"sha256": [
"43238d512c1e5eb2d6569f4a3afbf5523418b82e0a3ed1552770abb9a9c9ccab"
]
},
"usesPermission": [
{
"name": "android.permission.INTERNET"
},
{
"name": "android.permission.ACCESS_NETWORK_STATE"
},
{
"name": "android.permission.ACCESS_WIFI_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_MULTICAST_STATE"
},
{
"name": "android.permission.CHANGE_NETWORK_STATE"
},
{
"name": "android.permission.CHANGE_WIFI_STATE"
},
{
"name": "android.permission.BLUETOOTH"
},
{
"name": "android.permission.BLUETOOTH_ADMIN"
},
{
"name": "android.permission.RECEIVE_BOOT_COMPLETED"
},
{
"name": "android.permission.READ_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_EXTERNAL_STORAGE"
},
{
"name": "android.permission.WRITE_SETTINGS"
},
{
"name": "android.permission.NFC"
},
{
"name": "android.permission.USB_PERMISSION",
"maxSdkVersion": 22
},
{
"name": "android.permission.WAKE_LOCK"
},
{
"name": "android.permission.FOREGROUND_SERVICE"
}
],
"usesPermissionSdk23": [
{
"name": "android.permission.ACCESS_COARSE_LOCATION"
}
]
}
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
{
"packages": {
"org.fdroid.min1": {
"versions": {
"824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf": {
"added": 0,
"manifest": {
"versionName": "0",
"versionCode": 1
},
"file": {
"name": "/org.fdroid.min1_23.apk",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337
}
}
},
"metadata": {
"added": 0,
"lastUpdated": 0,
"license": ""
}
}
},
"repo": {
"name": "MinV1",
"icon": {
"name": "/icons/min-v1.png",
"sha256": "74758e480ae76297c8947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
},
"address": "https://min-v1.org",
"description": {
"en-US": "This is a repo with minimal data."
},
"timestamp": 42
}
}

View File

@@ -0,0 +1,34 @@
{
"repo": {
"timestamp": 42,
"version": 1,
"name": "MinV1",
"icon": "min-v1.png",
"address": "https://min-v1.org",
"description": "This is a repo with minimal data."
},
"requests": {
"install": [
],
"uninstall": [
]
},
"apps": [
{
"license": "",
"packageName": "org.fdroid.min1"
}
],
"packages": {
"org.fdroid.min1": [
{
"apkName": "org.fdroid.min1_23.apk",
"hash": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"hashType": "sha256",
"packageName": "org.fdroid.min1",
"size": 1337,
"versionName": "0"
}
]
}
}

View File

@@ -0,0 +1,38 @@
{
"repo": {
"name": "MinV1",
"icon": {
"name": "/icons/min-v1.png",
"sha256": "74758e480ae76297c8947f107db9ea03d2933c9d5c110d02046977cf78d43def",
"size": 0
},
"address": "https://min-v1.org",
"description": {
"en-US": "This is a repo with minimal data."
},
"timestamp": 42
},
"packages": {
"org.fdroid.min1": {
"metadata": {
"added": 0,
"lastUpdated": 0,
"license": ""
},
"versions": {
"824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf": {
"added": 0,
"file": {
"name": "/org.fdroid.min1_23.apk",
"sha256": "824a109b2352138c3699760e1683385d0ed50ce526fc7982f8d65757743374bf",
"size": 1337
},
"manifest": {
"versionName": "0",
"versionCode": 1
}
}
}
}
}
}