Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
e
os
App Lounge
Commits
d957da8d
Commit
d957da8d
authored
Jul 22, 2021
by
Aayush Gupta
Browse files
Merge branch 'squashed_fixups' into 'master'
Apps: Refactor applications verification logic See merge request e/apps/apps!72
parents
2acfe991
26f9ca21
Pipeline
#126127
passed with stage
in 6 minutes and 31 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
app/src/main/assets/systemApp.json
0 → 100644
View file @
d957da8d
{
"com.explusalpha.Snes9xPlus"
:{
"url"
:
"https://cleanapk.org/#/app/5b15b33a89bb693d3a3e806b"
,
"project_id"
:
"1001"
,
"app_name"
:
"Snes9x EX+"
}
}
\ No newline at end of file
app/src/main/java/foundation/e/apps/api/FDroidAppExistsRequest.kt
0 → 100644
View file @
d957da8d
/*
* Copyright (C) 2021 E FOUNDATION
* Copyright (C) 2021 ECORP SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package
foundation.e.apps.api
import
foundation.e.apps.utils.Common
import
foundation.e.apps.utils.Constants
import
foundation.e.apps.utils.Error
import
java.util.*
class
FDroidAppExistsRequest
(
private
val
keyword
:
String
)
{
fun
request
(
callback
:
(
Error
?,
ArrayList
<
Int
?>)
->
Unit
)
{
try
{
val
l1
=
ArrayList
<
Int
?>()
val
url
=
Constants
.
F_DROID_PACKAGES_URL
+
keyword
+
"/"
val
urlConnection
=
Common
.
createConnection
(
url
,
Constants
.
REQUEST_METHOD_GET
)
val
responseCode
=
urlConnection
.
responseCode
urlConnection
.
disconnect
()
l1
.
add
(
responseCode
)
callback
.
invoke
(
null
,
l1
)
}
catch
(
e
:
Exception
)
{
callback
.
invoke
(
Error
.
findError
(
e
),
ArrayList
())
}
}
}
\ No newline at end of file
app/src/main/java/foundation/e/apps/api/SystemAppExistsRequest.kt
0 → 100644
View file @
d957da8d
/*
* Copyright (C) 2021 E FOUNDATION
* Copyright (C) 2021 ECORP SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package
foundation.e.apps.api
import
foundation.e.apps.utils.Common
import
foundation.e.apps.utils.Constants
import
foundation.e.apps.utils.Error
import
java.util.*
class
SystemAppExistsRequest
(
private
val
keyword
:
String
)
{
fun
request
(
callback
:
(
Error
?,
ArrayList
<
String
?>)
->
Unit
)
{
try
{
val
l1
=
ArrayList
<
String
?>()
val
url
=
Constants
.
SYSTEM_PACKAGES_JSON_FILE_URL
val
urlConnection
=
Common
.
createConnection
(
url
,
Constants
.
REQUEST_METHOD_GET
)
val
data
=
urlConnection
.
inputStream
.
bufferedReader
().
readText
()
urlConnection
.
disconnect
()
l1
.
add
(
data
)
callback
.
invoke
(
null
,
l1
)
}
catch
(
e
:
Exception
)
{
callback
.
invoke
(
Error
.
findError
(
e
),
ArrayList
())
}
}
}
\ No newline at end of file
app/src/main/java/foundation/e/apps/application/model/IntegrityVerificationTask.kt
View file @
d957da8d
/*
* Copyright (C) 2019-2021 E FOUNDATION
* Copyright (C) 2021 ECORP SAS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -18,13 +19,18 @@
package
foundation.e.apps.application.model
import
android.content.Context
import
android.content.pm.PackageInfo
import
android.content.pm.PackageManager
import
android.content.pm.Signature
import
android.os.AsyncTask
import
android.os.Handler
import
android.os.Looper
import
android.util.Log
import
android.widget.Toast
import
foundation.e.apps.R
import
foundation.e.apps.api.FDroidAppExistsRequest
import
foundation.e.apps.api.SystemAppExistsRequest
import
foundation.e.apps.application.model.data.FullData
import
foundation.e.apps.utils.Constants
import
org.bouncycastle.jce.provider.BouncyCastleProvider
import
org.bouncycastle.openpgp.PGPCompressedData
import
org.bouncycastle.openpgp.PGPPublicKeyRingCollection
...
...
@@ -33,6 +39,8 @@ import org.bouncycastle.openpgp.PGPUtil
import
org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory
import
org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider
import
org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator
import
org.json.JSONException
import
org.json.JSONObject
import
java.io.BufferedInputStream
import
java.io.File
import
java.io.FileInputStream
...
...
@@ -40,36 +48,130 @@ import java.io.InputStream
import
java.security.MessageDigest
import
java.security.Security
class
IntegrityVerificationTask
(
private
val
applicationInfo
:
ApplicationInfo
,
private
val
fullData
:
FullData
,
private
val
integrityVerificationCallback
:
IntegrityVerificationCallback
)
:
AsyncTask
<
Context
,
Void
,
Context
>()
{
private
var
verificationSuccessful
:
Boolean
=
false
private
var
TAG
=
"IntegrityVerificationTask"
override
fun
doInBackground
(
vararg
context
:
Context
):
Context
{
if
(
fullData
.
packageName
==
Constants
.
MICROG_PACKAGE
)
{
verificationSuccessful
=
true
}
else
{
verificationSuccessful
=
if
(!
fullData
.
getLastVersion
()
!!
.
apkSHA
.
isNullOrEmpty
())
{
getApkFileSha1
(
applicationInfo
.
getApkOrXapkFile
(
context
[
0
],
fullData
,
fullData
.
basicData
))
==
fullData
.
getLastVersion
()
!!
.
apkSHA
try
{
verificationSuccessful
=
if
(
isSystemApplication
(
fullData
.
packageName
))
{
verifySystemSignature
(
context
[
0
])
}
else
if
(
isfDroidApplication
(
fullData
.
packageName
))
{
verifyFdroidSignature
(
context
[
0
])
}
else
{
checkGoogleApp
(
context
[
0
])
}
}
catch
(
e
:
Exception
){
e
.
printStackTrace
()
}
return
context
[
0
]
}
private
fun
checkGoogleApp
(
context
:
Context
):
Boolean
{
return
verifyShaSum
(
context
)
}
private
fun
verifyShaSum
(
context
:
Context
)
:
Boolean
{
if
(!
fullData
.
getLastVersion
()
!!
.
apkSHA
.
isNullOrEmpty
())
{
return
getApkFileSha1
(
applicationInfo
.
getApkOrXapkFile
(
context
,
fullData
,
fullData
.
basicData
))
==
fullData
.
getLastVersion
()
!!
.
apkSHA
}
return
false
}
private
fun
verifySystemSignature
(
context
:
Context
):
Boolean
{
if
(!
fullData
.
getLastVersion
()
?.
signature
.
isNullOrEmpty
())
{
return
fullData
.
getLastVersion
()
?.
signature
==
getSystemSignature
(
context
.
packageManager
)
?.
toCharsString
()
}
return
false
}
private
fun
getFirstSignature
(
pkg
:
PackageInfo
?):
Signature
?
{
return
if
(
pkg
?.
signatures
!=
null
&&
pkg
.
signatures
.
isNotEmpty
())
{
pkg
.
signatures
[
0
]
}
else
null
}
private
fun
getSystemSignature
(
pm
:
PackageManager
):
Signature
?
{
try
{
val
sys
=
pm
.
getPackageInfo
(
"android"
,
PackageManager
.
GET_SIGNATURES
)
return
getFirstSignature
(
sys
)
}
catch
(
e
:
PackageManager
.
NameNotFoundException
)
{
Log
.
d
(
TAG
,
"Unable to find the package: android"
)
}
return
null
}
private
fun
verifyFdroidSignature
(
context
:
Context
)
:
Boolean
{
Security
.
addProvider
(
BouncyCastleProvider
())
return
verifyAPKSignature
(
context
,
BufferedInputStream
(
FileInputStream
(
applicationInfo
.
getApkFile
(
context
,
fullData
.
basicData
).
absolutePath
)),
fullData
.
getLastVersion
()
!!
.
signature
.
byteInputStream
(
Charsets
.
UTF_8
),
context
.
assets
.
open
(
"f-droid.org-signing-key.gpg"
))
}
private
fun
isfDroidApplication
(
packageName
:
String
):
Boolean
{
var
fDroidAppExistsResponse
=
0
FDroidAppExistsRequest
(
packageName
)
.
request
{
applicationError
,
searchResult
->
when
(
applicationError
)
{
null
->
{
if
(
searchResult
.
size
>
0
)
{
fDroidAppExistsResponse
=
searchResult
[
0
]
!!
}
}
else
->
{
Log
.
e
(
TAG
,
applicationError
.
toString
())
}
}
}
return
fDroidAppExistsResponse
==
200
}
private
fun
isSystemApplication
(
packageName
:
String
):
Boolean
{
var
jsonResponse
=
""
SystemAppExistsRequest
(
packageName
)
.
request
{
applicationError
,
searchResult
->
when
(
applicationError
)
{
null
->
{
if
(
searchResult
.
size
>
0
)
{
jsonResponse
=
searchResult
[
0
].
toString
()
}
}
else
->
{
Log
.
e
(
TAG
,
applicationError
.
toString
())
}
}
}
try
{
if
(
packageName
==
JSONObject
(
jsonResponse
).
get
(
packageName
))
{
return
true
}
}
catch
(
e
:
Exception
)
{
if
(
e
is
JSONException
)
{
Log
.
d
(
TAG
,
"$packageName is not a system application"
)
}
else
{
Security
.
addProvider
(
BouncyCastleProvider
())
verifyAPKSignature
(
context
[
0
],
BufferedInputStream
(
FileInputStream
(
applicationInfo
.
getApkFile
(
context
[
0
],
fullData
.
basicData
).
absolutePath
)),
fullData
.
getLastVersion
()
!!
.
signature
.
byteInputStream
(
Charsets
.
UTF_8
),
context
[
0
].
assets
.
open
(
"f-droid.org-signing-key.gpg"
))
e
.
printStackTrace
()
}
}
return
context
[
0
]
return
false
}
override
fun
onPostExecute
(
context
:
Context
)
{
integrityVerificationCallback
.
onIntegrityVerified
(
context
,
verificationSuccessful
)
if
(!
verificationSuccessful
){
Toast
.
makeText
(
context
,
R
.
string
.
not_able_install
,
Toast
.
LENGTH_LONG
).
show
()
}
}
private
fun
getApkFileSha1
(
file
:
File
):
String
?
{
...
...
@@ -136,8 +238,7 @@ class IntegrityVerificationTask(
e
.
printStackTrace
()
Handler
(
Looper
.
getMainLooper
()).
post
{
val
toast
=
Toast
.
makeText
(
context
,
context
.
resources
.
getString
(
R
.
string
.
Signature_verification_failed
),
Toast
.
LENGTH_LONG
)
toast
.
show
()
Toast
.
makeText
(
context
,
context
.
resources
.
getString
(
R
.
string
.
Signature_verification_failed
),
Toast
.
LENGTH_LONG
).
show
()
}
}
...
...
app/src/main/java/foundation/e/apps/utils/Constants.kt
View file @
d957da8d
...
...
@@ -68,4 +68,8 @@ object Constants {
const
val
UPDATES_NOTIFICATION_CHANNEL_TITLE
=
"App updates"
const
val
UPDATES_NOTIFICATION_CLICK_EXTRA
=
"updates_notification_click_extra"
// Integrity Verification
const
val
F_DROID_PACKAGES_URL
=
"https://f-droid.org/en/packages/"
const
val
SYSTEM_PACKAGES_JSON_FILE_URL
=
"https://gitlab.e.foundation/e/apps/apps/-/raw/e169c1905114d97af867b051f96c38166f4782e2/app/src/main/assets/systemApp.json"
}
app/src/main/res/values/strings.xml
View file @
d957da8d
...
...
@@ -161,6 +161,7 @@
<string
name=
"error_incident"
>
An error occured
</string>
<string
name=
"image_carousel"
>
Image carousel
</string>
<string
name=
"divider"
>
Divider
</string>
<string
name=
"not_able_install"
>
Not able to install this application! verification failed
</string>
</resources>
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment