1
0
mirror of https://github.com/owncloud/android-library.git synced 2025-06-07 16:06:08 +00:00

Compare commits

...

634 Commits

Author SHA1 Message Date
Aitorbp
71224c30d1
Merge pull request #581 from owncloud/release/4.1
[RELEASE] 4.1 library to master
2023-09-05 09:49:55 +01:00
Aitorbp
c82d75b1d8 New fix for snackbar when copy without server on 2023-08-30 10:16:58 +01:00
Manuel Plazas Palacio
530999848f Solving bugs when getting file existence in OC10 2023-08-24 14:12:30 +02:00
Manuel Plazas Palacio
b4625d017c Solving bugs when getting file existence. 2023-08-24 12:28:23 +02:00
Manuel Plazas Palacio
2c698cc2a4
Merge pull request #578 from owncloud/feature/unneccesary_call
[BUG] unneccessary or wrong call ....
2023-08-23 10:56:22 +02:00
Manuel Plazas Palacio
bf183fe04d Solving bug when copyin or moving 2023-08-22 15:24:59 +02:00
Manuel Plazas Palacio
1f8de383b6 Removing extra path on check path existence. 2023-08-18 11:14:11 +02:00
Aitorbp
8eb435a1c2
Merge pull request #577 from owncloud/feature/respect_app_provider_values_from_capabilities
[FEATURE REQUEST] Respect app_provider values from capabilities
2023-08-03 08:26:26 +01:00
Aitorbp
052566d205 Added variable from local data source 2023-07-31 12:43:16 +01:00
Manuel Plazas Palacio
063c3fa9e9
Merge pull request #571 from owncloud/feature/copy_move_conflic_solved_users
[FEATURE REQUEST] Copy/move conflict solved by users
2023-06-21 08:33:47 +02:00
Manuel Plazas Palacio
fa143804d2 Solving CR changes. 2023-06-08 13:31:09 +02:00
Manuel Plazas Palacio
5b64876e2c Showing decision dialog when moving file conflict.
Solving errors when copying, replace and keep both.
2023-06-07 12:15:14 +02:00
Manuel Plazas Palacio
d81ca97f14 Showing decision dialog when copying file conflict. 2023-06-07 12:15:14 +02:00
Juan Carlos Garrote
5607f76a1d
Merge pull request #566 from owncloud/technical/min_sdk_23
[TECHNICAL] Upgrade min SDK to Android 6 (v23)
2023-05-25 14:03:37 +02:00
Juan Carlos Garrote
b4137502d2 Remove unnecessary code after upgrading to min SDK 23 2023-05-25 13:33:49 +02:00
Juan Carlos Garrote
261075a8ad Update minSdkVersion to 23 (Android 6) 2023-05-25 13:33:49 +02:00
Juan Carlos Garrote
c2874357f0
Merge pull request #569 from owncloud/release/4.0
[Release] 2.1
2023-05-25 13:30:31 +02:00
Juan Carlos Garrote
e6937b4210 Removed publicUpload parameter from public shares creation and update requests 2023-05-15 14:01:16 +02:00
Juan Carlos Garrote
89dd13cec4
Merge pull request #562 from owncloud/feature/create_file_web
[FEATURE REQUEST] Create new file via Open in Web
2023-05-04 09:11:24 +02:00
Juan Carlos Garrote
ab3a594e5c Create network call to create file via app provider 2023-04-14 11:02:21 +02:00
Juan Carlos Garrote
cbbe044212
Merge pull request #558 from owncloud/fix/unknown_error_message
[FIX] Introduce new error message for ProtocolException
2023-04-13 08:26:42 +02:00
Juan Carlos Garrote
17aa1ea7bd Introduce new error message for ProtocolException 2023-04-13 08:20:50 +02:00
Abel García de Prada
cbf6365e93
Merge pull request #559 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.10
Bump org.robolectric:robolectric from 4.9.2 to 4.10
2023-04-12 08:21:19 +02:00
dependabot[bot]
15bccd3f80
Bump org.robolectric:robolectric from 4.9.2 to 4.10
Bumps [org.robolectric:robolectric](https://github.com/robolectric/robolectric) from 4.9.2 to 4.10.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.9.2...robolectric-4.10)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-12 02:57:14 +00:00
Juan Carlos Garrote
8cee0a37a7
Merge pull request #553 from owncloud/feature/app_registry
[Feature] Open in specific web provider
2023-04-10 09:17:36 +02:00
Abel García de Prada
393ec6e07e Open file in web with a specific app 2023-04-05 16:16:50 +02:00
Abel García de Prada
f35daacdf1 Pleasure the lint 2023-04-05 16:16:50 +02:00
Abel García de Prada
2ac5cf0657 Move open in web operations to their proper location 2023-04-05 16:16:50 +02:00
Abel García de Prada
173b12eeca Retrieve the list of available apps to open in web 2023-04-05 16:16:50 +02:00
Juan Carlos Garrote
602ab41fcc
Merge pull request #555 from owncloud/feature/auth_webfinger_flow
Update WebFinger flow
2023-04-04 13:44:31 +02:00
Juan Carlos Garrote
3a27baad3a Fix WebfingerResponse tests 2023-04-04 11:51:06 +02:00
Abel García de Prada
14baadd7ea Webfinger calls won't follow redirections. Only working with 2XX 2023-03-31 09:41:57 +02:00
Abel García de Prada
fa65c1a84d
Merge pull request #551 from owncloud/feature/add_language_header
Add accept language header to all requests
2023-03-24 13:33:42 +01:00
Abel García de Prada
c429b575a9 Add accept language header to all requests 2023-03-24 08:31:34 +01:00
Abel García de Prada
f7d4d27ebb
Merge pull request #552 from owncloud/remove_drives_permission_parsing
Remove permission parsing from spaces.
2023-03-23 10:21:01 +01:00
Abel García de Prada
3681f1001a Remove permission parsing from spaces. Will be done via WebDav permissions 2023-03-22 15:23:57 +01:00
Abel García de Prada
ee5130d3e6
Merge pull request #550 from owncloud/technical/bump_target_sdk
[TECHNICAL] Bump target sdk to 33
2023-03-21 12:23:38 +01:00
Abel García de Prada
1f93cfaf52 Bump target sdk to 33 2023-03-16 13:06:00 +01:00
Juan Carlos Garrote
e6e30fc352
Merge pull request #549 from owncloud/release/2.1
[Release] 2.1 beta.1
2023-03-13 13:09:04 +01:00
Abel García de Prada
c53475da37 Removing quotas from webdav properties in regular propfinds 2023-03-10 12:47:35 +01:00
Abel García de Prada
c2f32b2a82
Merge pull request #548 from owncloud/technical/replace_kapt_with_ksp
[Technical] Replace kapt with ksp
2023-03-09 13:02:47 +01:00
Abel García de Prada
6846e25fa3 Replace kapt with ksp 2023-03-09 11:51:13 +01:00
Juan Carlos Garrote
0e9f9c6391
Merge pull request #530 from owncloud/spaces/main
[SPACES] Main features
2023-03-09 11:49:00 +01:00
Juan Carlos Garrote
159dcd6d68 Rename file to be the same as the class it contains 2023-03-09 09:43:07 +01:00
Juan Carlos Garrote
b660ee98fd Rename files to be the same as the classes they contain 2023-03-09 09:37:09 +01:00
Abel García de Prada
ff90598a2d Rename WebFinger classes to make them consistent 2023-03-09 09:19:25 +01:00
Abel García de Prada
0017079a69 Allow retrieval of several instances from webfinger 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
2458db1828 Fix to KtLint report 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
e6f3fd2e16 Upload workers and network operations adapted to spaces 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
a395787e0b Adapted copy operation for spaces 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
e9f291371d Move network operation adapted to spaces 2023-03-09 09:19:25 +01:00
Abel García de Prada
b65efc2b69 Allow downloads from specific WebDav urls 2023-03-09 09:19:25 +01:00
Abel García de Prada
78665e8cb0 Add support for spaces web dav specific urls to the rename operation 2023-03-09 09:19:25 +01:00
Abel García de Prada
9c844aae7e Support removal of files from specific space 2023-03-09 09:19:25 +01:00
Abel García de Prada
2c18e7b679 Added create folder operation support for specific space 2023-03-09 09:19:25 +01:00
Abel García de Prada
cb73d537e4 Allow support to read specific file from a space 2023-03-09 09:19:25 +01:00
Abel García de Prada
8e4f243031 Fix remote path retrieval. Now it depends on webdav url to support spaces 2023-03-09 09:19:25 +01:00
Abel García de Prada
a65a82cae0 Adapt the propfind to work with specific webdavurl from the space 2023-03-09 09:19:25 +01:00
Abel García de Prada
45f53656ba Update permissions parsing to latest api changes
Supports api renaming from grantedTo to grantedToIdentities on v1.0.1
https://github.com/owncloud/libre-graph-api/releases/tag/v1.0.1
2023-03-09 09:19:25 +01:00
Abel García de Prada
8a4fcb6550 Support shares space 2023-03-09 09:19:25 +01:00
Abel García de Prada
31ccf56e97 Fix parsing when space is disabled 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
0d7a49b3ff Some type changes and renamings 2023-03-09 09:19:25 +01:00
Abel García de Prada
7bb94cf289 Make quota attribute nullable. Its not mandatory 2023-03-09 09:19:25 +01:00
Abel García de Prada
b1a3402656 Create spaces fetch operation and spaces service 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
f0dda9eb8b Added trailing comma 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
4f001550f9 Save spaces-related capabilities in database 2023-03-09 09:19:25 +01:00
Juan Carlos Garrote
e30246c486
Merge pull request #547 from owncloud/release/2.0.3
[Release] 2.0.3
2023-03-07 18:20:51 +01:00
Abel García de Prada
602b7e7548 Show the url in the response http log too 2023-03-07 14:14:54 +01:00
Abel García de Prada
f8da84d0ad
Merge pull request #544 from owncloud/dependabot/gradle/com.android.tools.build-gradle-7.4.2
Bump com.android.tools.build:gradle from 7.4.1 to 7.4.2
2023-02-28 08:02:23 +01:00
dependabot[bot]
763005b051
Bump com.android.tools.build:gradle from 7.4.1 to 7.4.2
Bumps com.android.tools.build:gradle from 7.4.1 to 7.4.2.

---
updated-dependencies:
- dependency-name: com.android.tools.build:gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 02:57:18 +00:00
Abel García de Prada
d6f969bd91
Merge pull request #540 from owncloud/bump/kotlin_gradle
Bump kotlin version to 1.8.10
2023-02-14 10:17:37 +01:00
Abel García de Prada
4200ed324c Bump kotlin version to 1.8.10 2023-02-14 09:45:29 +01:00
Abel García de Prada
7ee2c5eb15
Merge pull request #535 from owncloud/dependabot/gradle/org.jlleitschuh.gradle-ktlint-gradle-11.1.0
Bump ktlint-gradle from 11.0.0 to 11.1.0
2023-01-30 10:47:27 +01:00
dependabot[bot]
b5cd4a1df2
Bump ktlint-gradle from 11.0.0 to 11.1.0
Bumps ktlint-gradle from 11.0.0 to 11.1.0.

---
updated-dependencies:
- dependency-name: org.jlleitschuh.gradle:ktlint-gradle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 02:11:34 +00:00
Abel García de Prada
8a8a931e66
Merge pull request #534 from owncloud/release/2.0.2
[Release] 2.0.2
2023-01-27 13:11:39 +01:00
Abel García de Prada
148a97cd32 Potential fix to oauth error after logging in for first time that makes user to reauthenticate 2023-01-26 14:36:38 +01:00
Abel García de Prada
00948ffd73
Merge pull request #528 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.9.2
Bump robolectric from 4.9.1 to 4.9.2
2023-01-09 08:34:18 +01:00
dependabot[bot]
118646290d
Bump robolectric from 4.9.1 to 4.9.2
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.9.1 to 4.9.2.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.9.1...robolectric-4.9.2)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-28 02:01:23 +00:00
Abel García de Prada
defa4d1469
Merge pull request #525 from owncloud/debug/connection_validator_logs
Add several logs to try to debug potential errors related to token refreshment
2022-12-21 12:15:35 +01:00
Abel García de Prada
3545686a31 Add several logs to try to debug potential errors related to oAuth 2022-12-21 11:32:55 +01:00
Abel García de Prada
b710070426
Merge pull request #524 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.9.1
Bump robolectric from 4.9 to 4.9.1
2022-12-20 12:58:27 +01:00
dependabot[bot]
a0750c613a
Bump robolectric from 4.9 to 4.9.1
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.9 to 4.9.1.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.9...robolectric-4.9.1)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-20 02:01:28 +00:00
Abel García de Prada
9df62a51f3
Merge pull request #523 from owncloud/fix/unshare_ocis
Unsharing wont return anything anymore since result object was not used
2022-12-19 08:29:11 +01:00
Abel García de Prada
fa7bfdd597 Unsharing wont return anything anymore since result object was not used 2022-12-15 15:26:37 +01:00
Abel García de Prada
cb076aa6b9
Merge pull request #520 from owncloud/dependencies/bump_bulk
Bump several dependencies at the same time
2022-12-15 14:49:39 +01:00
Abel García de Prada
7ceef58382 Bump gradle plugin to 7.3.1 and move package name fro manifest to gradle namespace 2022-12-13 19:00:10 +01:00
Abel García de Prada
a877612fca Bump several dependencies at the same time 2022-12-13 14:51:57 +01:00
Abel García de Prada
359e591275
Merge pull request #339 from owncloud/new_arch/synchronization
[New arch] Synchronization
2022-12-12 09:54:27 +01:00
Abel García de Prada
f9bc792ded Do data field not mandatory on ocs response 2022-11-28 19:35:47 +01:00
Juan Carlos Garrote
9adadbddcc Fix lint reports 2022-11-28 19:35:47 +01:00
Abel García de Prada
1ecb8020b1 Remove legacy KEY_OC_VERSION constant 2022-11-28 19:35:47 +01:00
Abel García de Prada
b7d3cc2687 Remove legacy owncloud version from the client. 2022-11-28 19:35:47 +01:00
Juan Carlos Garrote
2b27b9657c Increased the chunk size to 10 MB 2022-11-28 19:35:47 +01:00
Abel García de Prada
959cb7b015 Retrieve Etag from successful upload 2022-11-28 19:35:47 +01:00
Abel García de Prada
b59a4e6947 Read remote file function added to the file service 2022-11-28 19:35:47 +01:00
Abel García de Prada
17821e5760 Migrate ReadRemoteFileOperation to kotlin. Second step to keep git history 2022-11-28 19:35:47 +01:00
Abel García de Prada
2b79175b5a Migrate ReadRemoteFileOperation to kotlin. First step to keep git history 2022-11-28 19:35:47 +01:00
Abel García de Prada
b25fbc4604 Fix an error after rebasing with latest version 2022-11-28 19:35:47 +01:00
Abel García de Prada
79173af930 Polish a little bit the code 2022-11-28 19:35:47 +01:00
Abel García de Prada
c36eedd481 Return Unit when the upload operation succeeds 2022-11-28 19:35:47 +01:00
Abel García de Prada
ba37bce0e1 Add transfer listeners to content uri worker 2022-11-28 19:35:47 +01:00
Abel García de Prada
dc7022c531 Pleasure the ktlint 2022-11-28 19:35:47 +01:00
Abel García de Prada
1f499fb67d Make requireEtag nullable 2022-11-28 19:35:46 +01:00
Abel García de Prada
12040a1261 Migrate old request bodies from java to kotlin 2022-11-28 19:35:46 +01:00
Abel García de Prada
7e56412748 Move content uri request body to a new file 2022-11-28 19:35:46 +01:00
Abel García de Prada
71e9bbd2da Delete old java operations. Use the kotlin ones from now on 2022-11-28 19:35:46 +01:00
Abel García de Prada
cbbeaab251 Migrate remote chunk upload operation to kotlin 2022-11-28 19:35:46 +01:00
Abel García de Prada
340e114a91 Use extension to simplify a little bit the code 2022-11-28 19:35:46 +01:00
Abel García de Prada
c6584d69fd Migrate remote upload operation to kotlin 2022-11-28 19:35:46 +01:00
Abel García de Prada
4c39990edb Add copy operation to the file service 2022-11-28 19:35:46 +01:00
Abel García de Prada
34cc4c87b1 Refactor copy remote file operation. Make overwrite false as default to avoid some potential errors 2022-11-28 19:35:46 +01:00
Abel García de Prada
5449eb7480 Migrate CopyRemoteFileOperation to kotlin. Second step to keep git history 2022-11-28 19:35:46 +01:00
Abel García de Prada
33d6141613 Migrate CopyRemoteFileOperation to kotlin. First step to keep git history 2022-11-28 19:35:46 +01:00
Abel García de Prada
f7645c1648 Apply code review suggestions 2022-11-28 19:35:46 +01:00
Abel García de Prada
6f33dca672 Remove nullability from a variable 2022-11-28 19:35:46 +01:00
Abel García de Prada
6fb5350dea Add rename file to FileService 2022-11-28 19:35:46 +01:00
Abel García de Prada
24037a7a3e Migrate RenameRemoteFileOperation to kotlin. Second step to keep git history 2022-11-28 19:35:46 +01:00
Abel García de Prada
5f01b32b12 Migrate RenameRemoteFileOperation to kotlin. First step to keep git history 2022-11-28 19:35:46 +01:00
Abel García de Prada
f849cd76d4 Make overwrite option disabled by default for move operations 2022-11-28 19:35:46 +01:00
Abel García de Prada
7c825b2dc3 Add move operation to file service 2022-11-28 19:35:46 +01:00
Abel García de Prada
b3cccfa007 Add move operation to chunk service 2022-11-28 19:35:46 +01:00
Abel García de Prada
5beb30e07a Migrate MoveRemoteFileOperation to kotlin. Second step to keep git history 2022-11-28 19:35:46 +01:00
Abel García de Prada
d736c7cdbf Migrate MoveRemoteFileOperation to kotlin. First step to keep git history 2022-11-28 19:35:46 +01:00
Abel García de Prada
d99444e279 Apply code review suggestions 2022-11-28 19:35:46 +01:00
Abel García de Prada
86f16c3460 Add removeFile to FileService 2022-11-28 19:35:46 +01:00
Abel García de Prada
62dbdb1021 Converting RemoveRemoteFileOperation from java to kotlin. Final step. 2022-11-28 19:35:46 +01:00
Abel García de Prada
f706595a9a Converting RemoveRemoteFileOperation from java to kotlin. Intermediate step to preserve git history. 2022-11-28 19:35:46 +01:00
Abel García de Prada
03303ac4f2 Replace kotlin android extensions with kotlin-parcelize 2022-11-28 19:35:46 +01:00
Abel García de Prada
039245742c Apply code review suggestions 2022-11-28 19:35:46 +01:00
Abel García de Prada
3a996ef583 Download file operation will return unit instead of Any 2022-11-28 19:35:46 +01:00
agarcia
ec71fa6c23 Create parent folder when downloading a file if possible 2022-11-28 19:35:46 +01:00
agarcia
56248af6ec Add download file to file service 2022-11-28 19:35:46 +01:00
agarcia
389c0a0fc6 Migrate DownloadRemoteFileOperation to kotlin 2022-11-28 19:35:46 +01:00
Abel García de Prada
405da9a729 Apply CR changes 2022-11-28 19:35:46 +01:00
Abel García de Prada
a02844d2c7 Map size or length property depending on mimetype 2022-11-28 19:35:46 +01:00
Abel García de Prada
53c99a21c2 Transform RemoteFile to kotlin and apply necessary changes 2022-11-28 19:35:46 +01:00
agarcia
5e478036ae Apply code review suggestions 2022-11-28 19:28:41 +01:00
agarcia
cd94e39b7f Include createFolder as file service operation 2022-11-28 19:28:41 +01:00
agarcia
b0798194be Migrate CreateRemoteFolderOperation to kotlin 2022-11-28 19:28:41 +01:00
agarcia
2b5f80bdb9 Apply CR suggestions 2022-11-28 19:28:41 +01:00
agarcia
32891e2cf5 Add owner field to remote file 2022-11-28 19:28:41 +01:00
agarcia
d164b34fe8 Migrate ReadRemoteFolderOperation to kotlin and add it to FileService 2022-11-28 19:28:41 +01:00
Juan Carlos Garrote
c2f7426a3e
Merge pull request #515 from owncloud/feature/handle_425_response
Handle 425 TOO EARLY propfind responses
2022-11-17 13:15:10 +01:00
Juan Carlos Garrote
1e9d8cef42 Handle 425 when trying to open in web 2022-11-17 12:50:55 +01:00
Abel García de Prada
b083debac9 Handle 425 TOO EARLY propfind responses 2022-11-17 12:50:55 +01:00
Jesús Recio
376d52ac5b
Merge pull request #481 from owncloud/feature/webfinger
add moshi classes for webfinger responses
2022-11-02 11:16:57 +01:00
Abel García de Prada
e769684920 Reformat some webfinger classes 2022-10-13 10:22:39 +02:00
Abel García de Prada
70bf35f683 Remove unused imports 2022-10-11 18:00:03 +02:00
Abel García de Prada
1afa124b7d Add webfinger service and update the remote operation 2022-10-10 13:07:11 +02:00
Christian Schabesberger
f19b2355b4 create scaffold for webfinger request operation 2022-10-06 09:34:13 +02:00
Christian Schabesberger
c966bf14d0 add moshi classes for webfinger responses 2022-10-06 09:34:13 +02:00
Abel García de Prada
2c225d8e66
Merge pull request #509 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.9
Bump robolectric from 4.8.1 to 4.9
2022-10-03 09:32:24 +02:00
dependabot[bot]
f8a829d6b7
Bump robolectric from 4.8.1 to 4.9
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.8.1 to 4.9.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.8.1...robolectric-4.9)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-03 02:15:21 +00:00
Abel García de Prada
0ea053d612
Merge pull request #503 from owncloud/feature/open_in_web
[Feature] Open in web
2022-09-01 10:54:05 +02:00
Abel García de Prada
0be462c9aa Set private link capability to unknown type when it is not retrieved
The CapabilityBooleanType.fromBooleanValue set it to FALSE when the capability is not retrieved. We don't want this for this case. Probably neither for the rest, but changing that now would need deeper testing
2022-08-31 17:21:55 +02:00
Abel García de Prada
32ef5d2125 Add a new capability to allow/disallow private links 2022-08-31 17:21:55 +02:00
Abel García de Prada
6282fbd419 Add the open in web to the service facade 2022-08-31 17:21:55 +02:00
Abel García de Prada
6d235fe74a Add a new remote operation to retrieve the url to open a file with ocis provider 2022-08-31 17:21:55 +02:00
Abel García de Prada
9ab7c139e1 Retrieve the app providers from the capabilities 2022-08-31 17:21:55 +02:00
Abel García de Prada
24b850d20c
Merge pull request #496 from owncloud/propfind_with_shares
Retrieve share type directly within the propfind
2022-07-07 14:59:20 +02:00
Abel García de Prada
5be4eca0f7 Added a new property, so that, we can retrieve the shares within the propfind 2022-07-07 08:18:54 +02:00
Jesús Recio
2dc6f30a5e
Merge pull request #490 from owncloud/fix/eos
Fix unexpected end of stream when connecting with server
2022-05-31 11:48:55 +02:00
Abel García de Prada
f712a384cd Fix unexpected end of stream when connecting with server 2022-05-30 13:41:41 +02:00
Abel García de Prada
1f9bff1df0
Merge pull request #439 from owncloud/Modernize
Modernize
2022-05-30 09:36:35 +02:00
Hannes Achleitner
1412117dcd Android Arctic Fox 2022-05-30 09:12:42 +02:00
Hannes Achleitner
a054adc688 Java 8 is by default 2022-05-30 09:11:56 +02:00
Abel García de Prada
809e641b1a
Merge pull request #488 from owncloud/release/2.21-beta.1
[Release] 1.0.15-beta.1
2022-05-12 09:49:09 +02:00
Fernando Sanz
fd8caa42cb Updated versionCode and versionName 2022-05-11 09:53:47 +02:00
Abel García de Prada
45a9a190f8
Merge pull request #486 from owncloud/bump/kotlin_version
Bump kotlin version to 1.6.21
2022-05-09 14:43:16 +02:00
Abel García de Prada
2931a5494a Bump kotlin version to 1.6.21 2022-05-09 14:09:21 +02:00
Abel García de Prada
35fb64c1bd
Merge pull request #484 from owncloud/dependabot/gradle/org.jlleitschuh.gradle-ktlint-gradle-10.3.0
Bump ktlint-gradle from 10.2.1 to 10.3.0
2022-05-09 14:04:04 +02:00
dependabot[bot]
544fc6efd4
Bump ktlint-gradle from 10.2.1 to 10.3.0
Bumps ktlint-gradle from 10.2.1 to 10.3.0.

---
updated-dependencies:
- dependency-name: org.jlleitschuh.gradle:ktlint-gradle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-04 07:13:39 +00:00
Abel García de Prada
16c31988e0
Merge pull request #485 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.8.1
Bump robolectric from 4.8 to 4.8.1
2022-05-04 09:12:31 +02:00
dependabot[bot]
7fe41ce51c
Bump robolectric from 4.8 to 4.8.1
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.8 to 4.8.1.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.8...robolectric-4.8.1)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-04 02:08:05 +00:00
Abel García de Prada
aaafdb5ea2
Merge pull request #483 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.8
Bump robolectric from 4.7.3 to 4.8
2022-04-29 08:28:09 +02:00
dependabot[bot]
6e503c2cf7
Bump robolectric from 4.7.3 to 4.8
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.7.3 to 4.8.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.7.3...robolectric-4.8)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-29 02:44:52 +00:00
Abel García de Prada
4de236b3c7
Merge pull request #364 from owncloud/fix/okhttp_singleton
remove okhttp singleton
2022-04-27 18:35:58 +02:00
Abel García de Prada
f6eb631fbf Reformat some code 2022-04-25 08:41:14 +02:00
Christian Schabesberger
be758eb5ea apply requested changes 2022-04-25 08:41:14 +02:00
Christian Schabesberger
d16ab2e643 remove sample client yet again 2022-04-25 08:41:14 +02:00
Christian Schabesberger
105830e4f0 apply requested changes 2022-04-25 08:41:14 +02:00
Christian Schabesberger
09375ce053 rebase okhttp_signleton fix on top of connection validator
fix token oauth token refresh error

pleasure the linter
2022-04-25 08:41:14 +02:00
Christian Schabesberger
fc4ae27bbe remove redundant intercept of httpclient with httpmethod 2022-04-25 08:41:14 +02:00
Schabi
344c1e1136 apply required fixes 2022-04-25 08:41:14 +02:00
Schabi
79e4287223 clean up http client 2022-04-25 08:41:14 +02:00
Christian Schabesberger
0313c1e103 get okhttp singleton removal changes to compile 2022-04-25 08:41:14 +02:00
Abel García de Prada
06e361afaa
Merge pull request #479 from owncloud/rename_check_script
rename verify_licnese_script back to check_script
2022-04-22 10:57:49 +02:00
Christian Schabesberger
217216e43f rename verify_licnese_script to check_code_script 2022-04-22 09:44:28 +02:00
Abel García de Prada
060a988978
Merge pull request #478 from owncloud/bump/gradle_kotlin
Bump gradle and kotlin to the latest versions
2022-04-11 09:29:57 +02:00
Abel García de Prada
e0b81bd11a Bump kotlin to 1.6.20 2022-04-08 10:53:23 +02:00
Abel García de Prada
97a613f168 Bump target sdk to api 31 2022-04-08 09:48:29 +02:00
Abel García de Prada
d8ac22d57e
Merge pull request #450 from owncloud/connection_validator
Connection validator
2022-03-31 14:55:31 +02:00
Christian Schabesberger
7c77c267f9 apply changes according to review 2022-03-23 13:27:19 +01:00
Christian Schabesberger
2a4195c966 fix lint and compile issues 2022-03-23 13:27:18 +01:00
Christian Schabesberger
d9dce81ce7 add GetBaseUrlRemoteOperation 2022-03-23 13:26:58 +01:00
Christian Schabesberger
4f3e167efa fix spelling mistakes 2022-03-23 13:26:58 +01:00
Christian Schabesberger
fc8440cc01 remove debug statements 2022-03-23 13:26:58 +01:00
Christian Schabesberger
5ca99a0e69 update base url in active client after 301 redirect
reduce validation retry count
2022-03-23 13:26:58 +01:00
Christian Schabesberger
ce761aaec2 remove redirect code from owncloudclient use okhttp instead 2022-03-23 13:26:58 +01:00
Christian Schabesberger
c59d1540c7 clean up credentials stuff from owncloudclient 2022-03-23 13:26:58 +01:00
Christian Schabesberger
5582097ca1 get access token to update through connection validator
update token
2022-03-23 13:26:58 +01:00
Christian Schabesberger
e27a968ddb add update authToken code to connectionValidator 2022-03-23 13:26:58 +01:00
Christian Schabesberger
cfd69987e9 update session from APM while running the app 2022-03-23 13:26:57 +01:00
Christian Schabesberger
b2f6d7f3b1 make initial check with apm work though connection validator 2022-03-23 13:24:27 +01:00
Christian Schabesberger
7ccb86c153 stop validation process if failing 2022-03-23 13:24:27 +01:00
Christian Schabesberger
e878ad3931 make oidc discovery work again 2022-03-23 13:24:27 +01:00
Schabi
8d09a5c242 make initial connection using connection validator work 2022-03-23 13:24:27 +01:00
Christian Schabesberger
ddb15a33f1 try shifting over to connection validator for updating credentials
intermediate commit
2022-03-23 13:24:27 +01:00
Christian Schabesberger
c2c351c912 set max redirect count for owncloud client to 5 2022-03-23 13:24:27 +01:00
Christian Schabesberger
ca206173df create logic scaffold for connection validator get status.php with it 2022-03-23 13:24:27 +01:00
Christian Schabesberger
7e4b43e7cb prepare code for the inclusion of connection validator 2022-03-23 13:24:27 +01:00
Christian Schabesberger
0e82f983b5 remove OwnCloudClient factory 2022-03-23 13:24:27 +01:00
Christian Schabesberger
0d94058db9 remove retrive cookies from middleware 2022-03-23 13:24:27 +01:00
Christian Schabesberger
2f952a3a09 debug and add mutex for halding requiests 2022-03-23 13:24:27 +01:00
Christian Schabesberger
39b1fce7f6 init connectionvalidator 2022-03-23 13:24:27 +01:00
Abel García de Prada
351efb7bf2
Merge pull request #474 from owncloud/dependabot/gradle/com.facebook.stetho-stetho-okhttp3-1.6.0
Bump stetho-okhttp3 from 1.5.1 to 1.6.0
2022-03-10 11:30:54 +01:00
dependabot[bot]
2edfc17653
Bump stetho-okhttp3 from 1.5.1 to 1.6.0
Bumps [stetho-okhttp3](https://github.com/facebook/stetho) from 1.5.1 to 1.6.0.
- [Release notes](https://github.com/facebook/stetho/releases)
- [Changelog](https://github.com/facebook/stetho/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/stetho/compare/v1.5.1...v1.6.0)

---
updated-dependencies:
- dependency-name: com.facebook.stetho:stetho-okhttp3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-10 10:15:54 +00:00
Abel García de Prada
e0efa7b3ab
Merge pull request #472 from owncloud/feature/check_script
Feature/check script
2022-03-10 10:21:07 +01:00
Abel García de Prada
5ab6514164 Rename the script and function to clarify their purpose 2022-03-10 09:45:34 +01:00
Christian Schabesberger
194894637e fix wrongly licensed source files 2022-03-10 09:45:34 +01:00
Christian Schabesberger
c662383182 add mit license header to where it was missing 2022-03-10 09:45:34 +01:00
Christian Schabesberger
f8c7c12f5b add check_script 2022-03-10 09:45:34 +01:00
Abel García de Prada
61508c85d1
Merge pull request #469 from owncloud/feature/add_stetho
Feature/add stetho
2022-03-08 09:27:34 +01:00
Christian Schabesberger
5619c1daf8 apply code cleanup according to review 2022-03-08 08:59:10 +01:00
Christian Schabesberger
85a3918ff1 fix usage of debug interceptor 2022-03-08 08:59:10 +01:00
Christian Schabesberger
7e507abf32 add debug interceptor 2022-03-08 08:59:10 +01:00
Abel García de Prada
a7e9138593
Merge pull request #471 from owncloud/fix/remove_sample_client
remove sample client
2022-03-08 08:58:00 +01:00
Christian Schabesberger
0ae5cf5ca2 remove sample client 2022-03-08 08:49:26 +01:00
Abel García de Prada
063e7366e5
Merge pull request #473 from owncloud/dependabot/github_actions/actions/checkout-3
Bump actions/checkout from 2 to 3
2022-03-07 07:52:38 +01:00
dependabot[bot]
5cec7b43e2
Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 02:03:39 +00:00
Abel García de Prada
ff0cde35fe
Merge pull request #466 from owncloud/release/1.0.14
[Release] 1.0.14
2022-02-16 10:45:45 +01:00
Fernando Sanz
a9a6ca6d4e Upgraded versionName and versionNumber 2022-02-09 14:32:09 +01:00
Abel García de Prada
57882e793e
Merge pull request #464 from owncloud/FixLint
Fix lint warnings
2022-01-31 09:10:32 +01:00
Hannes Achleitner
7365c0b126 Fix lint warnings 2022-01-31 08:09:53 +01:00
Abel García de Prada
5bebbe2d3d
Merge pull request #461 from owncloud/dependabot/gradle/org.jlleitschuh.gradle-ktlint-gradle-10.2.1
Bump ktlint-gradle from 10.2.0 to 10.2.1
2022-01-10 09:23:40 +01:00
dependabot[bot]
3aa9e72a22
Bump ktlint-gradle from 10.2.0 to 10.2.1
Bumps ktlint-gradle from 10.2.0 to 10.2.1.

---
updated-dependencies:
- dependency-name: org.jlleitschuh.gradle:ktlint-gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-28 02:05:26 +00:00
Abel García de Prada
cc53ed6f68
Merge pull request #460 from owncloud/bump/kotlin_1.6.10
Bump kotlin version to 1.6.10
2021-12-23 10:34:59 +01:00
Abel García de Prada
377572e87a Bump kotlin version to 1.6.10 2021-12-23 09:31:34 +01:00
Abel García de Prada
9fc5ddbc39
Merge pull request #459 from hannesa2/Gradle-Log4j
Bump Gradle for Log4j
2021-12-23 08:37:55 +01:00
Hannes Achleitner
b649ee0ad6 Bump Gradle for Log4j
https://github.com/gradle/gradle/releases/tag/v7.3.3
2021-12-23 08:23:02 +01:00
Abel García de Prada
e6e763882c
Merge pull request #442 from owncloud/feature/avatar_capability_library
[Feature] Respect capability for Avatar support
2021-12-13 11:37:10 +01:00
Fernando Sanz
27e5d367af Ktlint fixes. 2021-12-13 08:53:18 +01:00
Fernando Sanz
2b299da415 Retrieve new capability to user's avatar. 2021-12-13 08:53:18 +01:00
Abel García de Prada
2c0745f20a
Merge pull request #454 from owncloud/dependabot/gradle/moshiVersion-1.13.0
Bump moshiVersion from 1.12.0 to 1.13.0
2021-12-10 08:30:20 +01:00
dependabot[bot]
1a4b98d232
Bump moshiVersion from 1.12.0 to 1.13.0
Bumps `moshiVersion` from 1.12.0 to 1.13.0.

Updates `moshi-kotlin` from 1.12.0 to 1.13.0
- [Release notes](https://github.com/square/moshi/releases)
- [Changelog](https://github.com/square/moshi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/moshi/compare/moshi-parent-1.12.0...moshi-parent-1.13.0)

Updates `moshi-kotlin-codegen` from 1.12.0 to 1.13.0
- [Release notes](https://github.com/square/moshi/releases)
- [Changelog](https://github.com/square/moshi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/moshi/compare/moshi-parent-1.12.0...moshi-parent-1.13.0)

---
updated-dependencies:
- dependency-name: com.squareup.moshi:moshi-kotlin
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.squareup.moshi:moshi-kotlin-codegen
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-10 02:09:45 +00:00
Abel García de Prada
aef967bf25
Merge pull request #452 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.7.3
Bump robolectric from 4.5.1 to 4.7.3
2021-12-02 08:52:35 +01:00
dependabot[bot]
5ce81e3b17
Bump robolectric from 4.5.1 to 4.7.3
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.5.1 to 4.7.3.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.5.1...robolectric-4.7.3)

---
updated-dependencies:
- dependency-name: org.robolectric:robolectric
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-02 02:08:45 +00:00
Abel García de Prada
4fa986e053
Merge pull request #448 from owncloud/gradle_7.3
Bump gradle version to 7.3
2021-11-17 13:18:31 +01:00
Abel García de Prada
5e8f0b8286 Bump gradle version to 7.3 2021-11-17 10:31:10 +01:00
Abel García de Prada
050b98f78b
Merge pull request #433 from owncloud/Gradle-7.2
Gradle 7.2
2021-11-17 10:03:53 +01:00
Hannes Achleitner
487c4f682a Gradle 7.2 2021-11-17 09:50:05 +01:00
Abel García de Prada
f75f64ab13
Merge pull request #434 from owncloud/api30
Api 30
2021-11-17 09:46:11 +01:00
Hannes Achleitner
dd088d7222 Api 30 2021-11-17 09:32:18 +01:00
Abel García de Prada
05705722ef
Merge pull request #447 from owncloud/bump_several_dependencies
Bump Kotlin version to 1.5.31
2021-11-17 09:19:36 +01:00
Abel García de Prada
36cf45c377 Bump some dependencies 2021-11-17 08:51:39 +01:00
Abel García de Prada
eea5240bd0
Merge pull request #441 from owncloud/release/1.0.13
[Release] 1.0.13
2021-11-15 11:22:22 +01:00
Fernando Sanz
20efe90e2d QA report (5) fixed 2021-11-08 13:37:52 +01:00
Abel García de Prada
83048b61d8 Update versionName and versionCode for a new stable release 2021-11-05 13:18:04 +01:00
Abel García de Prada
8a3ba16f96
Merge pull request #440 from owncloud/release/1.0.13_beta.1
[Release] 1.0.13-beta.1
2021-11-05 08:25:12 +01:00
Abel García de Prada
e6b3df103e Update versionCode and versionName 2021-11-03 18:23:58 +01:00
Abel García de Prada
37bae10618
Merge pull request #436 from owncloud/fix/final_chunk_size
Fix a protocol exception when uploading chunked files
2021-11-03 18:07:18 +01:00
Abel García de Prada
10e44627e1 Change last chunk size to fix a protocol exception when sending files 2021-09-28 10:58:32 +02:00
Abel García de Prada
1baeebe5ee
Merge pull request #430 from owncloud/feature/parse_shares
[FEATURE REQUEST] Use Moshi to parse shares
2021-09-24 11:49:33 +02:00
Abel García de Prada
fa7d83edb3
Merge pull request #432 from owncloud/dependabot/gradle/org.jlleitschuh.gradle-ktlint-gradle-10.2.0
Bump ktlint-gradle from 10.1.0 to 10.2.0
2021-09-09 08:10:44 +02:00
dependabot[bot]
46dcb4434d
Bump ktlint-gradle from 10.1.0 to 10.2.0
Bumps ktlint-gradle from 10.1.0 to 10.2.0.

---
updated-dependencies:
- dependency-name: org.jlleitschuh.gradle:ktlint-gradle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-09 02:06:37 +00:00
Fernando Sanz
3c46c95ac1 Code revision suggestions have been implemented. 2021-09-02 12:33:48 +02:00
Fernando Sanz
f14abb0bcd Code revision suggestions have been implemented. 2021-09-02 10:55:02 +02:00
Fernando Sanz
0895732ed4 Library's copyright has been modified and restored. 2021-09-01 13:23:49 +02:00
Fernando Sanz
91bd322b68 The ShareXMLParser has been removed from UpdateRemoteShareOperation.kt class. 2021-08-31 14:47:48 +02:00
Fernando Sanz
7baf3e43a5 The ShareXMLParser has been removed from RemoveRemoteShareOperation.kt class. 2021-08-31 12:37:36 +02:00
Fernando Sanz
6285c6c70a The ShareXMLParser has been removed from GetRemoteSharesForFileOperation.kt class. 2021-08-31 11:59:41 +02:00
Fernando Sanz
b40a394ab1 The ShareXMLParser has been removed from CreateRemoteShareOperation.kt class. 2021-08-31 10:43:29 +02:00
Fernando Sanz
037a2b30df Fixed some bugs on how to create shares. 2021-08-31 08:52:55 +02:00
Abel García de Prada
45fb12df0e Fix shares parsing 2021-08-27 15:38:49 +02:00
Fernando Sanz
27b18c33a9 The way to retrieve list of shares has been modified from java to kotlin and its result has been parsed to ShareResponse.kt object. 2021-08-27 14:08:58 +02:00
Christian Schabesberger
c24ffcfaa4
Merge pull request #425 from owncloud/fix/add_content_length_error
add error log when content-length not equal to transfaired bytes
2021-08-18 17:13:20 +02:00
Christian Schabesberger
fbf0fab800 add error log when content-length not equal to transfaired bytes 2021-08-17 12:41:35 +02:00
Abel García de Prada
5852921764
Merge pull request #420 from owncloud/release/1.0.12
[Release] 1.0.12
2021-07-20 12:55:28 +02:00
Abel García de Prada
7b5c070175 Update version name and version code 2021-07-15 09:55:21 +02:00
Abel García de Prada
650f348c35
Merge pull request #419 from owncloud/improvement/oauth2_pkce
Add PKCE support
2021-07-14 19:11:21 +02:00
Abel García de Prada
20070775d7 Add parameters required for PKCE 2021-07-14 12:40:08 +02:00
Abel García de Prada
593da77a04
Merge pull request #418 from owncloud/dependabot/gradle/kotlinVersion-1.5.21
Bump kotlinVersion from 1.5.20 to 1.5.21
2021-07-14 09:33:08 +02:00
dependabot[bot]
3025ddce23
Bump kotlinVersion from 1.5.20 to 1.5.21
Bumps `kotlinVersion` from 1.5.20 to 1.5.21.

Updates `kotlin-gradle-plugin` from 1.5.20 to 1.5.21
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.5.21/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.5.20...v1.5.21)

Updates `kotlin-stdlib-jdk8` from 1.5.20 to 1.5.21
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.5.21/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.5.20...v1.5.21)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin:kotlin-gradle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-14 07:06:34 +00:00
Abel García de Prada
ac2f837f9e
Merge pull request #414 from owncloud/new_arch/camera_uploads
[New arch] Camera Uploads
2021-07-14 09:05:36 +02:00
Abel García de Prada
22719c8f40 Return unit in the remote operation 2021-07-08 12:24:21 +02:00
Abel García de Prada
12b009e378 Update operation 2021-07-05 09:17:37 +02:00
Abel García de Prada
5c2be25d66 Override contentLength in content uri request body to fix uploads to ocis 2021-07-05 09:17:37 +02:00
Abel García de Prada
99e636e8f6 Add a new operation to upload files directly with a content uri 2021-07-05 09:17:37 +02:00
Abel García de Prada
022c486603
Merge pull request #415 from owncloud/bump_kotlin_gradle
Bump kotlin to 1.5.20
2021-07-02 13:07:53 +02:00
Abel García de Prada
b491641eff Bump kotlin to 1.5.20 2021-07-02 09:57:38 +02:00
Abel García de Prada
86bfc3383c
Merge pull request #410 from owncloud/dependabot/gradle/org.jlleitschuh.gradle-ktlint-gradle-10.1.0
Bump ktlint-gradle from 10.0.0 to 10.1.0
2021-06-04 08:20:47 +02:00
dependabot[bot]
58ac89cb30
Bump ktlint-gradle from 10.0.0 to 10.1.0
Bumps ktlint-gradle from 10.0.0 to 10.1.0.

---
updated-dependencies:
- dependency-name: org.jlleitschuh.gradle:ktlint-gradle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-03 06:49:43 +00:00
Abel García de Prada
cfe5793d0d
Merge pull request #409 from owncloud/bump/kotlin_version
Bump kotlin version and AS
2021-05-26 09:38:43 +02:00
Abel García de Prada
c02a4dea91 Bump kotlin version 2021-05-26 08:57:03 +02:00
Abel García de Prada
e9d23d9cd2
Merge pull request #403 from owncloud/Gradle-6.9
Gradle 6.9
2021-05-24 09:46:36 +02:00
Hannes Achleitner
93497ca225 Gradle 6.9
It comes with Apple Silicon support
2021-05-24 09:36:33 +02:00
Abel García de Prada
abdbdbe4cc
Merge pull request #405 from owncloud/release/1.0.11
[Release] 1.0.11
2021-05-24 08:25:39 +02:00
Abel García de Prada
351682cc7f Use userId instead of username to build the webdavurl 2021-05-21 13:16:04 +02:00
Abel García de Prada
634c4a0f93 Update version name and version code for release 1.0.11 2021-05-18 12:19:40 +02:00
Abel García de Prada
307bf93a40
Merge pull request #404 from owncloud/MoveToMavenCentral
MavenCentral
2021-05-17 09:11:21 +02:00
Hannes Achleitner
d0e50c4fca MavenCentral 2021-05-15 07:07:16 +02:00
Abel García de Prada
bf6f93ff1c
Merge pull request #396 from owncloud/fix/xodo_bug
fix xodo sync bug
2021-05-11 17:09:09 +02:00
Abel García de Prada
2c18ae4ebb Clean unused imports 2021-05-10 09:56:18 +02:00
Christian Schabesberger
594ed2ee1b fix xodo file sync bug 2021-04-30 15:58:42 +02:00
Abel García de Prada
ccaf5a8e0e
Merge pull request #392 from owncloud/fix/oidc_no_registration_endpoint
Make some fields not mandatory in discovery response
2021-04-22 13:48:22 +02:00
Abel García de Prada
8c4a2708c2 Make some fields not mandatory in discovery response 2021-04-22 12:50:27 +02:00
Abel García de Prada
3f8ddd0ba9
Merge pull request #391 from owncloud/ktLintLibraryCheck
ktLint check in library
2021-04-22 12:47:51 +02:00
Abel García de Prada
13344ae622 Fix lint errors 2021-04-21 18:59:17 +02:00
Abel García de Prada
845b61ea4d Enable import ordering rule 2021-04-21 18:44:48 +02:00
Hannes Achleitner
257f616b0f ktLint check in library 2021-04-14 10:33:49 +02:00
Abel García de Prada
7dc81fb74c
Merge pull request #390 from owncloud/ktLint
Fix some ktlint findings
2021-04-14 09:45:16 +02:00
Abel García de Prada
1287035311 Fix some ktlint findings 2021-04-12 08:18:32 +02:00
Abel García de Prada
5ca9d5e330
Merge pull request #388 from owncloud/bump_kotlin_version
Bump kotlin version
2021-04-06 11:32:26 +02:00
Abel García de Prada
7924561a62 Bump kotlin version 2021-04-06 09:55:19 +02:00
Abel García de Prada
aa65410535
Merge pull request #387 from owncloud/dependabot/gradle/moshiVersion-1.12.0
Bump moshiVersion from 1.11.0 to 1.12.0
2021-04-06 09:46:04 +02:00
dependabot[bot]
88bb79c5ea
Bump moshiVersion from 1.11.0 to 1.12.0
Bumps `moshiVersion` from 1.11.0 to 1.12.0.

Updates `moshi-kotlin` from 1.11.0 to 1.12.0
- [Release notes](https://github.com/square/moshi/releases)
- [Changelog](https://github.com/square/moshi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/moshi/compare/moshi-parent-1.11.0...parent-1.12.0)

Updates `moshi-kotlin-codegen` from 1.11.0 to 1.12.0
- [Release notes](https://github.com/square/moshi/releases)
- [Changelog](https://github.com/square/moshi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/moshi/compare/moshi-parent-1.11.0...parent-1.12.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-05 09:33:44 +00:00
Abel García de Prada
87aa7137e7
Merge pull request #385 from owncloud/ktLintFindings
Fix ktlint findings
2021-04-05 08:21:24 +02:00
Hannes Achleitner
4df880357c Fix ktlint findings 2021-03-24 11:37:48 +01:00
JuancaG05
d1765eefb3
Merge pull request #384 from owncloud/bump_gradle_version
Bump gradle version to 1.4.3
2021-03-23 11:54:47 +01:00
Abel García de Prada
bf0ff3ce11 Bump gradle version to 1.4.3 2021-03-23 10:06:58 +01:00
Abel García de Prada
286fd65aff
Merge pull request #377 from owncloud/dependabot/gradle/org.robolectric-robolectric-4.5.1
Bump robolectric from 4.3.1 to 4.5.1
2021-03-22 15:07:30 +01:00
dependabot[bot]
a5574e1e45
Bump robolectric from 4.3.1 to 4.5.1
Bumps [robolectric](https://github.com/robolectric/robolectric) from 4.3.1 to 4.5.1.
- [Release notes](https://github.com/robolectric/robolectric/releases)
- [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.3.1...robolectric-4.5.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-22 11:27:08 +00:00
Abel García de Prada
0daa19cf90
Merge pull request #380 from owncloud/release/1.0.10
[Release] 1.0.10
2021-03-22 11:23:32 +01:00
Abel García de Prada
663e067d08 Update client with latest url 2021-03-16 12:40:51 +01:00
Abel García de Prada
a60c4909f4 Prepare 1.0.10 release 2021-03-16 11:11:39 +01:00
Abel García de Prada
b96a3e9be3
Merge pull request #376 from owncloud/release/1.0.10_beta.1
[RELEASE] 1.0.10-beta.1
2021-03-09 15:11:36 +01:00
Abel García de Prada
46495e0df2 Update versionCode and versionName 2021-03-08 16:26:20 +01:00
Abel García de Prada
87a05491ab
Merge pull request #368 from owncloud/fix/cookie_handling
[Fix] Cookie handling
2021-03-08 15:01:02 +01:00
Abel García de Prada
f248448e08 Update licenses, naming and apply CR suggestions 2021-03-02 10:35:51 +01:00
Abel García de Prada
3a79a86cd7 Fix 301 redirections 2021-03-02 10:34:39 +01:00
Abel García de Prada
1194b9a412 Use the same ownCloudClient across the whole login process 2021-03-02 10:34:39 +01:00
Christian Schabesberger
2a23a1c773 remove result from status requester 2021-03-02 10:34:39 +01:00
Schabi
9ad0e8f9bc apply codereview 2021-03-02 10:34:39 +01:00
Schabi
61ee5aab91 add test from redirect from http to http 2021-03-02 10:34:39 +01:00
Schabi
950d3a50da fix wrong handling of redirect to unsecure connection 2021-03-02 10:34:39 +01:00
Schabi
8eaa98af30 accept ssl connections for status when OK is returned 2021-03-02 10:34:39 +01:00
Abel García de Prada
6ea9f9996d Fix problem during rebase 2021-03-02 10:34:39 +01:00
Christian Schabesberger
f9ea701e2f remove cookie persistence 2021-03-02 10:34:38 +01:00
Christian Schabesberger
51dacd0bb0 remove KEY_OC_VERSION key 2021-03-02 10:34:38 +01:00
Christian Schabesberger
033e6822a2 prevent acumulating cookies on account change 2021-03-02 10:34:38 +01:00
agarcia
f8904dca9d Make get cookies static 2021-03-02 10:34:38 +01:00
Christian Schabesberger
654efea7e5 add tests for cookie jar 2021-03-02 10:34:38 +01:00
Christian Schabesberger
c3189b7b46 replace old cookies but don't delete them 2021-03-02 10:34:38 +01:00
agarcia
c54f1c98f6 Update some tests naming and remove unused dependencies 2021-03-02 10:34:38 +01:00
Christian Schabesberger
cba63c060f use robolectric for android tests 2021-03-02 10:34:38 +01:00
Christian Schabesberger
d0a710e31b add fixes according to review 2021-03-02 10:33:49 +01:00
Christian Schabesberger
91c7900d5c fix ip address without http prefix not recognized 2021-03-02 10:33:49 +01:00
Christian Schabesberger
b207fd1c67 fix rellative redirect 2021-03-02 10:33:49 +01:00
Christian Schabesberger
dac7bcc0e7 pleasure the linter 2021-03-02 10:33:49 +01:00
Christian Schabesberger
270e127940 fix according to review 2021-03-02 10:33:49 +01:00
Christian Schabesberger
84240ef78b detach request logic from operation 2021-03-02 10:33:49 +01:00
Christian Schabesberger
9d4b88cad7 refactor run function 2021-03-02 10:33:49 +01:00
Christian Schabesberger
cbfd977350 clean up tryConnect function 2021-03-02 10:33:49 +01:00
Christian Schabesberger
257cbcff03 add basic test functionality for andorid library 2021-03-02 10:33:49 +01:00
Christian Schabesberger
cc91ad9dde add fix for redirect, untested 2021-03-02 10:33:49 +01:00
Abel García de Prada
9ffe758dca
Merge pull request #374 from owncloud/dependabot/gradle/junit-junit-4.13.2
Bump junit from 4.13.1 to 4.13.2
2021-03-02 10:33:23 +01:00
dependabot[bot]
e821bee594
Bump junit from 4.13.1 to 4.13.2
Bumps [junit](https://github.com/junit-team/junit4) from 4.13.1 to 4.13.2.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.13.1...r4.13.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-02 08:31:56 +00:00
Abel García de Prada
4676eb48d7
Merge pull request #373 from owncloud/dependabot/gradle/moshiVersion-1.11.0
Bump moshiVersion from 1.9.2 to 1.11.0
2021-03-02 09:31:02 +01:00
dependabot[bot]
38d4dd604e
Bump moshiVersion from 1.9.2 to 1.11.0
Bumps `moshiVersion` from 1.9.2 to 1.11.0.

Updates `moshi-kotlin` from 1.9.2 to 1.11.0
- [Release notes](https://github.com/square/moshi/releases)
- [Changelog](https://github.com/square/moshi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/moshi/compare/moshi-parent-1.9.2...moshi-parent-1.11.0)

Updates `moshi-kotlin-codegen` from 1.9.2 to 1.11.0
- [Release notes](https://github.com/square/moshi/releases)
- [Changelog](https://github.com/square/moshi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/square/moshi/compare/moshi-parent-1.9.2...moshi-parent-1.11.0)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-02 08:13:05 +00:00
Abel García de Prada
0a31a1d3ef
Merge pull request #375 from owncloud/dependabot/gradle/kotlinVersion-1.4.31
Bump kotlinVersion from 1.4.30 to 1.4.31
2021-03-02 09:12:20 +01:00
dependabot[bot]
97df0b655d
Bump kotlinVersion from 1.4.30 to 1.4.31
Bumps `kotlinVersion` from 1.4.30 to 1.4.31.

Updates `kotlin-gradle-plugin` from 1.4.30 to 1.4.31
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.4.31/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.4.30...v1.4.31)

Updates `kotlin-stdlib-jdk8` from 1.4.30 to 1.4.31
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/v1.4.31/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.4.30...v1.4.31)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-02 07:00:20 +00:00
Abel García de Prada
ec4c0b2a7f
Merge pull request #371 from owncloud/Dependabot
Introduce dependabot
2021-02-23 13:03:01 +01:00
Abel García de Prada
e438ded413
Merge pull request #367 from owncloud/feature/oidc_dynamic_client_registration
[FEATURE] OIDC Dynamic Client Registration
2021-02-22 17:19:08 +01:00
Hannes Achleitner
94065ae449 Introduce dependabot 2021-02-18 08:32:51 +01:00
Abel García de Prada
37250fc55c Apply CR suggestions 2021-02-10 14:04:05 +01:00
Abel García de Prada
f35f41688a Create remote operation to register clients dynamically. 2021-02-10 14:04:05 +01:00
Abel García de Prada
3b138e7c01
Merge pull request #370 from owncloud/bump/kotlin_version
Bump kotlinVersion from 1.4.21 to 1.4.30
2021-02-09 12:52:53 +01:00
Abel García de Prada
67699ffcc0 Bump kotlinVersion from 1.4.20 to 1.4.30 2021-02-09 12:19:18 +01:00
Abel García de Prada
8e38c26374
Merge pull request #369 from owncloud/Modernize
Android Studio and Gradle update
2021-02-05 08:18:32 +01:00
Hannes Achleitner
e792cf6c70 Android Studio 4.1.2 2021-02-02 17:27:36 +01:00
Hannes Achleitner
fbbb1c9adb Gradle 6.8.1 2021-02-02 17:27:13 +01:00
Abel García de Prada
0e325cabd6
Merge pull request #363 from owncloud/feature/oauth_custom_implementation
[Feature] OAuth2 - OIDC Custom implementation
2021-02-02 09:36:04 +01:00
Abel García de Prada
9ae720502f Apply Code Review suggestions 2021-01-26 17:08:28 +01:00
Abel García de Prada
0d09540f9b Apply suggestions from CR 2021-01-26 17:08:28 +01:00
Abel García de Prada
44a13f9878 Polish a little bit the code 2021-01-26 17:08:28 +01:00
Abel García de Prada
df8e10fac3 Polish code. Send only info required for each type of request 2021-01-26 17:08:28 +01:00
Abel García de Prada
9208af89fe Support refresh token with any idP 2021-01-26 17:08:28 +01:00
Abel García de Prada
d683da3602 Support refresh token with own idP 2021-01-26 17:08:28 +01:00
Abel García de Prada
44967be4e3 First draft of request token implementation 2021-01-26 17:08:28 +01:00
Abel García de Prada
f289746c2f Use ownCloud client base url to perform oidc discovery 2021-01-26 17:08:28 +01:00
Abel García de Prada
0fc3f7668d Use the same ownCloudClient across the whole login process 2021-01-26 17:08:28 +01:00
Abel García de Prada
18b271665d Get OIDC discovery config 2021-01-26 17:08:28 +01:00
Abel García de Prada
c3ffe3d916
Merge pull request #365 from owncloud/release/1.0.9
[Release] 1.0.9
2021-01-26 12:44:02 +01:00
Abel García de Prada
65a4aaac28 Release 1.0.9 Update versionName and versionCode 2021-01-18 09:21:47 +01:00
Abel García de Prada
7ccda7d249
Merge pull request #362 from owncloud/fix/ocis_size
Use constants instead of hardcoded values for dir mimetypes
2021-01-14 13:44:16 +01:00
Abel García de Prada
114a7221f3 Use constants instead of hardcoded values for dir mimetypes 2020-12-22 10:50:20 +01:00
Abel García de Prada
6253f1e198
Merge pull request #361 from hannesa2/LiveLogcat
Show logcat live
2020-12-18 10:13:49 +01:00
Hannes Achleitner
cd8878352d delete logcat history 2020-12-16 14:09:22 +01:00
Hannes Achleitner
2a4f8175da Show logcat live
It updates logcat content during observation
2020-12-16 11:33:48 +01:00
Abel García de Prada
9bef933428
Merge pull request #360 from owncloud/AndroidStudio-4.1.1
Android Studio 4.1.1
2020-12-15 11:13:57 +01:00
Abel García de Prada
102747c392 Android Studio 4.1.1 2020-12-02 15:32:31 +01:00
Abel García de Prada
ceee204399
Merge pull request #358 from owncloud/feature/redirection_callback_brandable
Move appauth dependency to ownCloudApp
2020-12-02 15:31:08 +01:00
Abel García de Prada
0eeb48f7de Move appauth dependency to ownCloudApp 2020-12-02 14:57:17 +01:00
Abel García de Prada
a18528effc
Merge pull request #355 from owncloud/fix/parse_shareid_as_string
Parse shareId as String
2020-12-01 17:28:10 +01:00
Abel García de Prada
20c7c88a1f Remove item_source and file_source 2020-11-03 18:31:51 +01:00
Abel García de Prada
3441f4048c Convert long shareId to String 2020-11-03 11:46:44 +01:00
Abel García de Prada
af579a3fd0
Merge pull request #352 from owncloud/new_arch/moshi_parse_sharees
[New arch] Use moshi to parse sharees
2020-10-29 13:15:24 +01:00
Christian Schabesberger
68b88775e6 apply changes acording to review 2020-10-29 12:37:27 +01:00
Christian Schabesberger
ce9fc3f189 apply changes acording to review 2020-10-29 12:37:27 +01:00
Christian Schabesberger
257494a9dc apply suggested changes
delete unused const values

bla
2020-10-29 12:37:27 +01:00
Christian Schabesberger
6ec1bd2bb2 move response json to resource folder 2020-10-29 12:37:26 +01:00
Christian Schabesberger
76c55c9a9c add changes according to review 2020-10-29 12:37:26 +01:00
Christian Schabesberger
db478efedc refactor ShareType 2020-10-29 12:37:26 +01:00
Christian Schabesberger
29de5aba34 disable unitTestBinaryResource as its deprecated 2020-10-29 12:37:26 +01:00
Christian Schabesberger
34bf83df30 make sharee parts non null that can't be null 2020-10-29 12:37:26 +01:00
Christian Schabesberger
90b6ff52f2 add aditional data field to ocs sharees 2020-10-29 12:37:26 +01:00
Christian Schabesberger
26def4fbe2 return sharees without exact match 2020-10-29 12:37:26 +01:00
Christian Schabesberger
7402c89a18 get flat representation from ShareeOcsResponse 2020-10-29 12:37:26 +01:00
Christian Schabesberger
fe425c8083 update shareeservice to use ShareeOcsResponse 2020-10-29 12:37:26 +01:00
Christian Schabesberger
b86638412e update GetRemoteShareesOperation to use moshi 2020-10-29 12:37:26 +01:00
Christian Schabesberger
1c08a942d1 test model 2020-10-29 12:37:26 +01:00
Christian Schabesberger
6bdb2badca add support for tests 2020-10-29 12:37:26 +01:00
Christian Schabesberger
9f1c20b418 add Sharee response model 2020-10-29 12:37:26 +01:00
Christian Schabesberger
4f72f93f8b clean run method by braking down into small functions 2020-10-29 12:37:26 +01:00
Christian Schabesberger
8a04231473 move responses models into module folder 2020-10-29 12:37:26 +01:00
Abel García de Prada
61937825b8
Merge pull request #345 from owncloud/add_network_logs
Log network calls
2020-10-28 13:18:18 +01:00
Abel García de Prada
2b64b83b89 Do not log Authorization header 2020-10-28 09:17:27 +01:00
Abel García de Prada
5e86e9f0e4 Determine if a body is loggable based on its content-type 2020-10-28 09:04:17 +01:00
Abel García de Prada
460f85f2e1 Remove binary file logs 2020-10-27 16:12:23 +01:00
Abel García de Prada
943c5ecb97 Fix typo 2020-10-27 16:09:01 +01:00
Abel García de Prada
781f958c93 Do not log chunk request body 2020-10-23 11:39:24 +02:00
Abel García de Prada
db97ed7fb3 Fix response log marked as request one 2020-10-21 18:21:39 +02:00
Abel García de Prada
197c86ec64 Add LogInterceptor as NetworkInterceptor 2020-10-21 15:59:39 +02:00
Abel García de Prada
c0d2e20bb1 Log http body if it is not binary 2020-10-21 15:39:48 +02:00
Abel García de Prada
aa665a7295 Show request headers and body properly 2020-10-20 11:31:52 +02:00
Abel García de Prada
dc39475760 Add log interceptor disabled by default 2020-10-19 09:00:26 +02:00
Abel García de Prada
b7fd663d77 Improve http logs 2020-10-19 09:00:26 +02:00
Abel García de Prada
dc215dc80e Add a new variable to enable or disable http logs 2020-10-19 09:00:26 +02:00
Abel García de Prada
a564f18f16 Http logs enabled only in debug versions 2020-10-19 09:00:26 +02:00
agarcia
775fdb080c Add first draft to log network calls 2020-10-19 09:00:26 +02:00
Abel García de Prada
e28335ae4e
Merge pull request #351 from owncloud/update_dependencies
Update dependencies and perform a little cleanup
2020-10-16 15:04:03 +02:00
Abel García de Prada
4b6946a195 Update dependencies and perform a little cleanup 2020-10-14 16:22:20 +02:00
Abel García de Prada
5d21f01f38
Merge pull request #346 from owncloud/release/1.0.8
[Release] 1.0.8
2020-10-01 13:59:27 +02:00
agarcia
4d22971de0 Upgrade version code and version name 2020-09-30 16:52:50 +02:00
Abel García de Prada
411364b378
Merge pull request #344 from owncloud/remove_single_cookie_header
Remove single cookie header
2020-09-30 16:42:12 +02:00
agarcia
a55498c64b Remove single cookie header 2020-09-30 08:36:12 +02:00
Abel García de Prada
8da24c5076
Merge pull request #340 from owncloud/release/1.0.7
[Release] 1.0.7
2020-09-04 13:47:58 +02:00
agarcia
154507773d Upgrade version code and version name 2020-09-03 13:58:28 +02:00
Abel García de Prada
925f1e79aa
Merge pull request #330 from owncloud/UpdateLogcat
Update logcat
2020-08-12 18:25:59 +02:00
Hannes Achleitner
6d5d90d58c Update logcat 2020-08-12 15:58:38 +02:00
Abel García de Prada
f184347235
Merge pull request #333 from owncloud/release/1.0.6
[Release] 1.0.6
2020-08-12 13:50:51 +02:00
agarcia
a7a269a9e4 Fix timestamps 2020-08-11 18:40:17 +02:00
agarcia
f09162b213 Fix redirections 2020-08-04 17:27:58 +02:00
agarcia
31d3bfbde9 Move RequestBody to constructor to avoid npe 2020-08-04 17:27:58 +02:00
agarcia
f89cfd91a9 Reformat some code thanks to code review 2020-08-04 17:27:58 +02:00
agarcia
69497645ec Update dav4android and fix timestamp error depending on locale 2020-08-04 17:27:58 +02:00
agarcia
c5891b0a14 Remove interceptor and fix some errors related with shares 2020-08-04 17:27:58 +02:00
agarcia
b287cb9148 Compile project with latest changes from OkHttp and dav4jvm 2020-08-04 17:27:58 +02:00
agarcia
93026e8180 First step to replace interceptor 2020-08-04 17:27:58 +02:00
agarcia
c5cf0a8c0f Migrate http methods to kotlin 2020-08-04 17:27:57 +02:00
agarcia
aebd7288cd Migrate DavUtils to kotlin and fix a compilation error 2020-08-04 17:27:57 +02:00
agarcia
7f2d94bc78 Migrate webdav wrappers to kotlin 2020-08-04 17:27:57 +02:00
agarcia
c5fd59c825 Add support for version.hide config 2020-08-04 17:27:57 +02:00
agarcia
f93887732c Fix path dav4android -> dav4jvm 2020-08-04 17:27:57 +02:00
agarcia
ffe7d9d8e3 Update dav4android and okttp versions to 4.6.0 2020-08-04 17:27:57 +02:00
agarcia
390ef9fbd7 Update versionCode and versionName 2020-08-04 17:27:57 +02:00
Abel García de Prada
6cb2642ba1
Merge pull request #337 from owncloud/AndroidStudio_4.0.1
Android Studio 4.0.1
2020-08-04 17:15:08 +02:00
agarcia
ceab9378ab Update Android Studio to 4.0.1 2020-08-04 16:17:15 +02:00
Abel García de Prada
137b417580
Merge pull request #331 from owncloud/fix/refresh_basic_credentials
[Fix] Refresh credentials
2020-07-01 08:45:36 +02:00
agarcia
23a38a7fe6 Refresh stored client credentials when needed 2020-06-30 18:32:38 +02:00
Abel García de Prada
cdd16046a8
Merge pull request #329 from owncloud/UseAndroidSeparator
Use Android separator instead of homemade one
2020-06-30 12:50:56 +02:00
Hannes Achleitner
070ac89fa9 Use Android separator instead of homemade one 2020-06-25 06:14:16 +02:00
Abel García de Prada
d28927712c
Merge pull request #327 from owncloud/new_arch/sync_user
[New Arch] Sync user profile
2020-06-22 12:17:21 +02:00
agarcia
7536ba8f3c Apply code review suggestions 2020-06-16 17:21:15 +02:00
agarcia
d6ea5800eb Take care when quota available and used are 0 2020-06-16 17:21:15 +02:00
agarcia
59229aa6ab Remove avatar dimension from Service constructor 2020-06-16 17:21:15 +02:00
agarcia
ac21650da7 Manage responses with no avatar 2020-06-16 17:21:15 +02:00
agarcia
d997c84a80 Keep working on avatar rearquitecture 2020-06-16 17:21:15 +02:00
agarcia
6f74907af6 Migrate GetRemoteUserAvatarOperation to kotlin 2020-06-16 17:21:15 +02:00
agarcia
8a88fbd938 Apply CR suggestions 2020-06-16 17:21:15 +02:00
agarcia
bbac8d0278 Polish remote operation 2020-06-16 17:21:15 +02:00
agarcia
337c57da1a Include GetQuota in UserService 2020-06-16 17:21:15 +02:00
agarcia
85782e4818 Migrate GetRemoteUserQuotaOperation to kotlin 2020-06-16 17:21:15 +02:00
Abel García de Prada
e5e226dee0
Merge pull request #325 from owncloud/feature/android10
Upgrade target version to v29
2020-06-16 17:16:34 +02:00
agarcia
76a808cb0d Use TLSv1.3 if available 2020-06-15 14:16:45 +02:00
agarcia
7710db7612 Upgrade target version to v29 2020-06-09 11:26:23 +02:00
Abel García de Prada
d157c107c8
Merge pull request #322 from owncloud/AndroidStudio-4.0
Android Studio 4.0
2020-06-09 11:24:53 +02:00
agarcia
5ef9243a53 Update gradle to 6.5 2020-06-08 09:55:36 +02:00
Hannes Achleitner
f77de321b7 Android Studio 4.0 2020-06-08 09:37:06 +02:00
Abel García de Prada
d6eb080389
Merge pull request #319 from owncloud/release/1.0.5
[Release] 1.0.5
2020-06-03 11:14:11 +02:00
agarcia
1cee1a7a65 Update versionCode and versionName 2020-05-27 12:54:34 +02:00
Abel García de Prada
8708af1cfd
Merge pull request #321 from owncloud/release/1.0.5_beta.2
[Release] 1.0.5 beta 2
2020-05-22 14:58:22 +02:00
agarcia
e2f858238b Add chunking capability 2020-05-15 10:10:18 +02:00
Abel García de Prada
0e39f949e5
Merge pull request #318 from owncloud/cleanup/remove_unused_capabilities
Removed unused capabilities
2020-05-15 08:43:46 +02:00
agarcia
837aa39b23 Removed unused capabilities 2020-05-14 09:58:28 +02:00
agarcia
fc8c256463 Update versionCode and versionName 2020-05-12 13:09:21 +02:00
Abel García de Prada
8228374d71
Merge pull request #316 from owncloud/release/1.0.5_beta.1
[Release] 1.0.5 beta 1
2020-05-06 14:57:41 +02:00
agarcia
fba6436b56 Update versionCode and versionName 2020-05-06 13:59:06 +02:00
Abel García de Prada
9e9877f2bf
Merge pull request #298 from owncloud/feature/use_moshi_to_parse_capabilities
Use Moshi to parse Capabilities
2020-05-05 10:37:40 +02:00
agarcia
42b923c3b8 Allow capabilities to be null 2020-05-05 08:51:39 +02:00
agarcia
679b91df7c Apply CR suggestions 2020-05-05 08:51:39 +02:00
agarcia
b10e74afec Use moshi to parse capabilities 2020-05-05 08:51:39 +02:00
abelgardep
7b29f8f09e Create a common response to parse json 2020-05-05 08:51:39 +02:00
abelgardep
48ee263951 First attempt to use Moshi to parse capabilities 2020-05-05 08:51:39 +02:00
Abel García de Prada
0f10c725c7
Merge pull request #317 from owncloud/AndroidStudio3.6.3
Update Android Studio to 3.6.3
2020-05-05 08:39:19 +02:00
agarcia
7f7fa0b74e Update Android Studio to 3.6.3 2020-04-30 12:18:47 +02:00
Abel García de Prada
8f62925312
Merge pull request #315 from owncloud/oidc_new_arch
Open Id Connect along with new arch in login
2020-04-29 18:31:30 +02:00
davigonz
d957d48279 Move some OAuth constants out of the library 2020-04-29 17:32:54 +02:00
davigonz
7b32f7bbe4 Move OAuthConnectionBuilder to presentation layer, along with the rest of AppAuth dependencies 2020-04-29 17:32:54 +02:00
davigonz
5371c682d4 Add oidc scope constant 2020-04-29 17:32:54 +02:00
davigonz
f20d2554bf Fix crash when response body is empty and solve issue when retrieving auth methods 2020-04-29 17:32:54 +02:00
Abel García de Prada
64bfd6a7f7
Merge pull request #314 from owncloud/fix/short_names_not_found_as_recipients
Remove search min length capability
2020-04-22 11:02:22 +02:00
agarcia
54d03cdfd5 Remove search min length capability 2020-04-22 10:07:03 +02:00
David González Verdugo
5ecd3c9311
Merge pull request #307 from owncloud/new_arch/login
[New arch] Login
2020-04-17 15:41:01 +02:00
agarcia
9e46b83901 A little cleanup 2020-04-16 14:31:08 +02:00
davigonz
18b0abb01a Apply CR changes 2020-04-16 14:31:08 +02:00
davigonz
bec5643714 Include services implementation so that can be used by library users 2020-04-16 14:31:08 +02:00
davigonz
cf06126ce1 Move account version constant to a better place within AccountUtils 2020-04-16 14:31:08 +02:00
davigonz
0028d63292 Create account version constant 2020-04-16 14:31:08 +02:00
agarcia
c6e88b127c Fix a potential null pointer exception 2020-04-16 14:31:08 +02:00
agarcia
d2ee1294f2 Rename services 2020-04-16 14:31:08 +02:00
agarcia
7e6b63db1f A little cleanup and improve some log messages 2020-04-16 14:31:08 +02:00
agarcia
1536a455a6 Move constants and utils to proper files 2020-04-16 14:31:08 +02:00
agarcia
4f07187fa2 Rename remote operations 2020-04-16 14:31:08 +02:00
Abel García de Prada
3829a1ca32 Start working on login usecase 2020-04-16 14:31:08 +02:00
abelgardep
ec5c9fc4aa Remove ugly dependency from GetRemoteStatusOperation
Create AnonymousService for operations that not require authentication
2020-04-16 14:31:08 +02:00
abelgardep
ad533c8307 Migrate GetRemoteStatusOperation to Kotlin 2020-04-16 14:31:08 +02:00
abelgardep
921983c16e Migrate ExistenceCheckRemoteOperation to Kotlin 2020-04-16 14:31:08 +02:00
abelgardep
99ced8bf41 Refactor GetRemoteUserInfoOperation
Start using Moshi to parse json responses.
Create RemoteUserInfo and UserInfoResponse.
Create UserService.
Migrate GetRemoteUserInfoOperation to kotlin.
2020-04-16 14:31:08 +02:00
Abel García de Prada
c5e64bd7ac
Merge pull request #312 from owncloud/fix/parseFileItemSourceAsString
Parse file_source and item_source as string
2020-04-16 09:28:10 +02:00
Abel García de Prada
96ea90e349
Merge pull request #305 from owncloud/verify-gradle
verify Gradle
2020-04-15 13:34:31 +02:00
agarcia
18f4775db6 Perform gradle validation only on pr 2020-04-15 11:20:42 +02:00
agarcia
9ec6e74d6e Parse file_source and item_source as string 2020-04-15 10:50:53 +02:00
Hannes Achleitner
ffcf603b8b verify Gradle 2020-04-08 10:39:22 +02:00
Abel García de Prada
9331f7e8b3
Merge pull request #310 from owncloud/AndroidStudio-3.6.1
Android Studio 3.6.2
2020-04-07 08:13:52 +02:00
agarcia
48f720011d Use last kotlin version 2020-04-06 08:52:32 +02:00
Hannes Achleitner
1945d311d7 Android Studio 3.6.1 2020-03-17 18:08:00 +01:00
Jesús Recio Rincón
1d767f1e13
Merge pull request #296 from owncloud/UpdateCopyRightYear
Update Copyright year to 2020 (library)
2020-03-17 17:51:17 +01:00
Hannes Achleitner
6803a347bf Update Copyright year to 2020 2020-03-17 15:50:50 +01:00
Abel García de Prada
e6e3af2082
Merge pull request #311 from owncloud/fix/support_for_special_username
Support for usernames with character +
2020-03-12 11:10:58 +01:00
agarcia
8d5524da75 Support for usernames with character + 2020-03-10 14:19:40 +01:00
David González Verdugo
f7a54a8218
Merge pull request #306 from owncloud/fix/sample_client
Fix sample client
2020-02-18 16:48:22 +01:00
davigonz
e343a720f7 Fix sample client 2020-02-18 12:18:02 +01:00
David González Verdugo
8f9bed2d9f
Merge pull request #300 from owncloud/new_arch/oauth_app_auth
Implement OAuth2 with AppAuth
2020-02-12 18:27:52 +01:00
davigonz
0f1f232c16 Fix crash when client is revoked from web UI 2020-02-12 10:51:49 +01:00
davigonz
4a9eb24d69 Include hostname verifier 2020-02-11 16:46:15 +01:00
David González Verdugo
b77cecedab
Merge pull request #294 from owncloud/preventCrash
prevent a crash
2020-02-11 08:39:56 +01:00
davigonz
1b4ce388b3 Apply changes requested in code review 2020-02-06 15:03:50 +01:00
davigonz
4153ee4e35 Remove no longer used OAuth classes 2020-02-05 17:16:06 +01:00
davigonz
261be8bf85 Create OAuth scope param to save it in AccountManager during OAuth process 2020-02-05 16:32:50 +01:00
davigonz
b7033e53bf Use custom connection builder to work with http requests along with AppAuth library 2020-02-05 10:16:33 +01:00
David González Verdugo
fb8dc389a4
Merge pull request #301 from owncloud/fix/oauth_multiaccount
Fix multiaccount with OAuth does not work + Owncloud Client factories cleanup
2020-02-05 09:48:26 +01:00
davigonz
b04a314478 Remove unnecessary method 2020-02-05 08:49:24 +01:00
davigonz
c7f9c9d201 Clean up owncloud client factories 2020-02-04 17:49:35 +01:00
davigonz
5b3c21ba82 Change policy name in ownCloudClientManagerFactory 2020-02-04 15:33:00 +01:00
Hannes Achleitner
e2be78c8f8 prevent a crash 2020-01-30 22:33:43 +01:00
David González Verdugo
015011b6e0
Merge pull request #297 from owncloud/BuildSampleApp
Build sample app successful
2020-01-30 14:40:34 +01:00
davigonz
ffbd4e9128 Use latest gradle version 2020-01-28 17:33:16 +01:00
Abel García de Prada
11a2ec1d3e Replace stacktrace with timber log 2020-01-21 13:11:54 +01:00
Hannes Achleitner
9beb25d019 fix lint issues 2020-01-21 13:10:01 +01:00
Hannes Achleitner
a47d6fd882 switch to Timber 2020-01-21 13:10:01 +01:00
Hannes Achleitner
4e03070641 delete old maven relict 2020-01-21 13:10:01 +01:00
Hannes Achleitner
b72353f025 Android Studio 3.5.3 2020-01-21 13:10:01 +01:00
Hannes Achleitner
2aec82b5e2 cleanup .gitignore 2020-01-21 13:10:01 +01:00
Abel García de Prada
6df51cc323
Merge pull request #286 from owncloud/remove_older_10_support
End of support for <10 servers
2020-01-20 13:28:40 +01:00
davigonz
4cd317d929 Fix build after rebasing with master 2020-01-17 11:13:21 +01:00
Abel García de Prada
03e30ae698 Fix log with old server version 2020-01-16 15:13:41 +01:00
Abel García de Prada
52463707c7 Remove unused constants 2020-01-16 15:13:41 +01:00
davigonz
20e4317bd9 Include new isServerVersionSupported parameter to log out <10 accounts 2020-01-16 15:13:41 +01:00
davigonz
8ba4fa5960 Handle specific bad request error 2020-01-16 15:13:41 +01:00
David González
495e3321e2 Fix folder creation 2020-01-16 15:11:43 +01:00
davigonz
234add959a Apply changes requested in PR 2020-01-16 15:11:11 +01:00
davigonz
bcc5a06335 Get rid of conditions for <10 servers 2020-01-16 15:09:11 +01:00
David González Verdugo
285306e1bc
Merge pull request #293 from owncloud/replace_logOC_with_timber
Replace Log_OC with timber
2020-01-15 16:18:05 +01:00
Abel García de Prada
073a91c580 Update logcat library 2020-01-15 12:20:46 +01:00
Abel García de Prada
c0a11c5d0b Remove Log_OC file 2020-01-15 12:20:46 +01:00
Abel García de Prada
c5ac449fed Replace log_oc with timber
Finish replacing logOC with timber
2020-01-15 12:20:46 +01:00
Abel García de Prada
2778762217 Remove logging initialization from Log_OC 2020-01-15 12:18:00 +01:00
David González Verdugo
a63dd63b39
Merge pull request #295 from owncloud/fixTypo
fix a typo and some lint warnings
2020-01-14 16:33:29 +01:00
David González Verdugo
d76ecc3bc6
Merge pull request #291 from owncloud/FixCompleteBuild
Finish remove Android 4.4 support
2020-01-13 10:25:28 +01:00
Hannes Achleitner
3204d5e60e fix a typo and some lint warnings 2020-01-02 12:31:20 +01:00
Hannes Achleitner
a1d4c781ae Finish remove Android 4.4 support 2019-12-19 13:03:24 +01:00
David González Verdugo
fadc578f07
Merge pull request #290 from owncloud/release_1.0.4.1
Release 1.0.4.1
2019-12-19 12:04:59 +01:00
davigonz
9a806469c5 Rename 10 version constant 2019-12-19 10:53:51 +01:00
davigonz
169836683e Update versionName and versionCode 2019-12-19 10:53:51 +01:00
davigonz
094e698e95 Include field to know servers lower than 10 2019-12-19 10:53:51 +01:00
David González Verdugo
66c8b906fa
Merge pull request #284 from owncloud/ReduceLogging
Reduce logging in ChunkFromFileRequestBody
2019-12-18 08:52:51 +01:00
Hannes Achleitner
90210949b5 Reduce logging in ChunkFromFileRequestBody
(cherry picked from commit 53a8ce122c7f0d4ef6d47e76a29b15fc68197135)
2019-12-17 18:58:00 +01:00
David González Verdugo
e5939e8b70
Merge pull request #285 from owncloud/feature/stop_supporting_android_kitkat
Get rid of Android 4.4 support
2019-12-17 17:49:16 +01:00
David González Verdugo
3262ad4c48
Merge pull request #287 from owncloud/release_1.0.4
[Release] 1.0.4
2019-12-17 12:34:58 +01:00
davigonz
fdeb504d87 Update versionName and versionCode to 1.0.4 2019-12-11 12:46:13 +01:00
Abel García de Prada
3d9d943825 Remove kitkat support 2019-12-11 12:37:30 +01:00
David González Verdugo
a708b794c0
Merge pull request #278 from owncloud/new_arch/modularization
[New arch] Modularization
2019-12-11 11:55:25 +01:00
davigonz
1aeacd62b8 Apply changes requested in code review 2019-12-05 08:50:55 +01:00
Abel García de Prada
9710cf991d Update remote capability 2019-12-05 08:50:55 +01:00
davigonz
da08f04fa1 Fix capability type 2019-12-05 08:50:54 +01:00
davigonz
f104d6842e Clean up remote objects (code review) 2019-12-05 08:50:54 +01:00
davigonz
c50e199b76 Fix null error in http interceptors 2019-12-05 08:50:54 +01:00
davigonz
c05a11a7b4 Create some service interfaces as facade for remote operations 2019-12-05 08:50:54 +01:00
davigonz
8fa6cc648b Fix add headers using interceptors 2019-12-05 08:50:54 +01:00
davigonz
27ff4dfd23 Fix upload 2019-12-05 08:50:54 +01:00
davigonz
28d93a6790 Update RemoteCapability with new search min characters field 2019-12-05 08:50:54 +01:00
davigonz
f32a3af572 Uncomplished commit 2019-12-05 08:50:54 +01:00
davigonz
9ea10e2f96 Remove dependency between the library and the domain layer 2019-12-05 08:50:54 +01:00
davigonz
2e460d9cf7 Include mapper for remote capabilities 2019-12-05 08:50:54 +01:00
davigonz
9230937a44 Keep decoupling shares and capabilities, start to use mappers 2019-12-05 08:50:54 +01:00
davigonz
d73ee43e3d Handle remote operations, both sync and non-sync 2019-12-05 08:50:54 +01:00
davigonz
9aff678fa4 Delete GetRemoteSharesOperation 2019-12-05 08:50:54 +01:00
davigonz
cc38dcd9a6 Include a new class to give data or throw remote exceptions to upper layers 2019-12-05 08:50:54 +01:00
davigonz
32ecf729c5 Keep removing more SAML stuff 2019-12-05 08:50:54 +01:00
davigonz
31868dca00 Start to use Mockk instead of Mockito since is better prepared to be used along with Kotlin 2019-12-05 08:50:54 +01:00
davigonz
66490ff2b0 Update gradle version 2019-12-05 08:50:54 +01:00
davigonz
ebf1a08508 Remove unused OwnCloudClient constructor 2019-12-05 08:50:54 +01:00
davigonz
ea34453f0a Delete unneeded extend 2019-12-05 08:50:54 +01:00
davigonz
5981dfab96 Remove OpenForTesting, no longer needed since mockk is used 2019-12-05 08:50:54 +01:00
davigonz
e28ffbac7c Make some classes opened for testing 2019-12-05 08:50:54 +01:00
David González Verdugo
3d7a04a12d
Merge pull request #283 from owncloud/BetterLogging
Better logging (on upstream)
2019-11-27 18:53:55 +01:00
davigonz
5bf99df58a Update Logcat library dependency 2019-11-26 16:47:15 +01:00
Hannes Achleitner
10a7bdbc4d delete all *.log in directory 2019-11-22 23:35:26 +01:00
Hannes Achleitner
fa4db38a41 fix progress dialog and 'No adapter attached' 2019-11-20 07:51:07 +01:00
Hannes Achleitner
b084ca7c03 introduce deprecated old and new methods 2019-11-15 08:16:14 +01:00
Hannes Achleitner
d32f35147f remove some pointless warnings 2019-11-15 07:51:01 +01:00
Hannes Achleitner
035c5fdf65 Better logging 2019-11-15 07:51:01 +01:00
Abel García de Prada
07e00a720d
Merge pull request #235 from hannesa2/cleanupCode
code cleanup
2019-11-12 12:50:18 +01:00
Hannes Achleitner
68063fa9fa apply review suggestion 2019-11-09 10:05:16 +01:00
Hannes Achleitner
fdde542f15 code cleanup 2019-11-09 10:03:02 +01:00
Jesús Recio Rincón
e2f1637c80
Merge pull request #273 from hannesa2/AndroidStudio-3.5.1
Android Studio 3.5.2
2019-11-07 13:43:43 +01:00
Hannes Achleitner
eb177543fc Android Studio 3.5.2 2019-11-06 06:25:21 +01:00
Hannes Achleitner
2913176f81 Android Studio 3.5.1 2019-10-30 23:01:52 +01:00
David González Verdugo
c67fa8b7b1
Merge pull request #270 from owncloud/min_number_of_characters_to_search
Add min number of character to search capability
2019-10-14 09:17:09 +02:00
Abel García de Prada
87d244e473 Add min number of character to search capability 2019-10-11 14:39:24 +02:00
David González Verdugo
fca43e1fb8
Merge pull request #272 from owncloud/revert_compileSdkVersion_28
Revert compileSdkVersion to 28
2019-10-10 14:28:55 +02:00
davigonz
d0eb8293fd Rever compileSdkVersion to 28 2019-10-10 14:13:13 +02:00
David González Verdugo
fc8c54f142
Merge pull request #267 from owncloud/release_1.0.3
[Release] 1.0.3
2019-09-26 12:24:38 +02:00
davigonz
bb45bc9dbb Update version number and name 2019-09-24 17:13:50 +02:00
David González Verdugo
2dcfcc2545
Merge pull request #266 from hannesa2/AndroidStudio-3.5.0
Android Studio 3.5.0
2019-09-24 09:42:09 +02:00
David González Verdugo
2b62387e80
Merge pull request #260 from owncloud/document_provider/copy
[Document Provider] Copy
2019-09-12 10:11:15 +02:00
Hannes Achleitner
b66a82e1de stay on target 28 2019-09-11 22:51:02 +02:00
Hannes Achleitner
159bc0789e Kotlin 1.3.50 2019-09-08 09:25:54 +02:00
Hannes Achleitner
36df3d9287 Android Studio 3.5.0 2019-09-08 09:25:39 +02:00
davigonz
90cef9fcf6 Use remoteId of the just copied file 2019-08-28 11:56:26 +02:00
David González Verdugo
07cdef9afa
Merge pull request #261 from owncloud/test_get_rid_of_gravis
Get rid of Travis
2019-08-28 10:34:59 +02:00
davigonz
8db0b820ff Delete .travis.yml 2019-08-26 15:28:18 +02:00
David González Verdugo
14e99551a9
Merge pull request #258 from owncloud/release_1.0.2
[Release] 1.0.2
2019-08-21 17:24:27 +02:00
230 changed files with 9028 additions and 9905 deletions

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

5
.editorconfig Normal file
View File

@ -0,0 +1,5 @@
[*]
max_line_length = 150
[*.{kt, kts}]
disabled_rules=no-consecutive-blank-lines,no-wildcard-imports,max-line-length,no-blank-line-before-rbrace,final-newline,indent,no-multi-spaces,comment-spacing,parameter-list-wrapping

17
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,17 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gradle"
directory: "/" # Location of package manifests
schedule:
interval: "daily"
labels:
- "dependencies"
- package-ecosystem: "github-actions"
directory: "/" # Location of package manifests
schedule:
interval: "weekly"

View File

@ -0,0 +1,10 @@
name: "Validate Gradle Wrapper"
on: [pull_request]
jobs:
validation:
name: "Validation"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1

5
.gitignore vendored
View File

@ -19,11 +19,6 @@ gen/
# Local configuration files (sdk path, etc)
.gradle/
local.properties
sample_client/local.properties
# Mac .DS_Store files
.DS_Store
# Proguard README
proguard-project.txt
sample_client/proguard-project.txt

View File

@ -2,17 +2,11 @@
<code_scheme name="Project" version="173">
<option name="LINE_SEPARATOR" value="&#10;" />
<option name="RIGHT_MARGIN" value="150" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<JavaCodeStyleSettings>
<option name="FIELD_NAME_PREFIX" value="m" />
<option name="STATIC_FIELD_NAME_PREFIX" value="s" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99999" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
@ -40,36 +34,9 @@
<MarkdownNavigatorCodeStyleSettings>
<option name="RIGHT_MARGIN" value="72" />
</MarkdownNavigatorCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
<XML>
<option name="XML_ATTRIBUTE_WRAP" value="0" />
<option name="XML_KEEP_BLANK_LINES" value="1" />
<option name="XML_ALIGN_ATTRIBUTES" value="false" />
<option name="XML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="JAVA">
@ -244,7 +211,6 @@
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>

View File

@ -1,44 +0,0 @@
sudo: false
language: android
jdk:
- oraclejdk8
branches:
only:
- master
install:
# Let's use the new command 'sdkmanager' to install Android SDK components
- yes | sdkmanager --verbose "build-tools;26.0.3"
- yes | sdkmanager --verbose "platform-tools"
- yes | sdkmanager --verbose "tools"
- yes | sdkmanager --verbose "platforms;android-26"
- yes | sdkmanager --verbose "system-images;android-24;default;armeabi-v7a"
# Check tools and dependencies installed
- yes | sdkmanager --list
# After Travis updated image with Android base environment, building via ant is not possible anymore.
# Port library tests to new-style with JUnit 4 and gradle build.
- rm pom.xml
# On the other hand, Travis still uses 'android' command behind the 'components' section update.
# That command is obsolete and cannot update Android SDK Tools after 25.2.5.
# Let's solve it here with the new command 'sdkmanager'
- yes | sdkmanager --verbose tools
script:
- ./gradlew clean build
env:
global:
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
# via the "travis encrypt" command using the project repo's public key
- secure: epTZ0zZGDbHL3o6vSC9uNkZsi5j5SA6O/tvQBH7QW/dluuzIJxIjfhNbZHDyBReYDleirLzUFQpdWAUdvulCMLs/qZdIzFGlYXZSpxEnvPYMGQcilwADdJcxLw8L+3+ET5hSexxhjrTGw427IljkqGUpqQTxaLwFdFu98lDWSbc=
matrix:
- ANDROID_TARGET=android-26 ANDROID_ABI=armeabi-v7a
addons:
coverity_scan:
project:
name: owncloud/android-library
description: Build submitted via Travis CI
notification_email: lukas@owncloud.com
build_command_prepend: gradle clean
build_command: gradle build
branch_pattern: coverity_scan

View File

@ -2,7 +2,7 @@
ownCloud Android Library is available under MIT license
Copyright (C) 2019 ownCloud GmbH.
Copyright (C) 2020 ownCloud GmbH.
Copyright (C) 2012 Bartek Przybylski
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@ -44,11 +44,11 @@ ownCloud Android Library is available under MIT license. See the file LICENSE.md
#### Third party libraries
ownCloud Android Library uses OkHttp version 3.10, licensed under Apache License and version 2.0. Besides, it uses Dav4Android, licensed under Mozilla Public License, v. 2.0
ownCloud Android Library uses OkHttp version 4.6.0, licensed under Apache License and version 2.0. Besides, it uses Dav4Android, licensed under Mozilla Public License, v. 2.0
### Compatibility
ownCloud Android Library is valid for Android systems from version Android 2.2 (android:minSdkVersion="8" android:targetSdkVersion="19").
ownCloud Android Library is valid for Android systems from version Android 6 (android:minSdkVersion="23" android:targetSdkVersion="33").
ownCloud Android library supports ownCloud server from version 4.5.

View File

@ -1,24 +1,34 @@
buildscript {
ext {
// Libraries
kotlinVersion = '1.3.21'
orgJetbrainsKotlin = '1.8.10'
comSquareupMoshi = '1.14.0'
}
repositories {
google()
jcenter()
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion"
classpath "org.jlleitschuh.gradle:ktlint-gradle:11.1.0"
classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$orgJetbrainsKotlin"
}
}
plugins {
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
subprojects {
apply plugin: "org.jlleitschuh.gradle.ktlint"
apply plugin: "com.google.devtools.ksp"
}

15
check_code_script.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/bash
check_license_in_file() {
if ! head -n 20 $FILE | grep -q "Permission is hereby granted, free of charge, to any person obtaining a copy"
then
echo "$FILE does not contain a current copyright header"
fi
}
for FILE in $(find owncloudComLibrary/src -name "*.java" -o -name "*.kt")
do
check_license_in_file
done
./gradlew ktlintFormat

3
gradle.properties Normal file
View File

@ -0,0 +1,3 @@
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M

Binary file not shown.

View File

@ -1,6 +1,5 @@
#Wed Aug 17 12:51:45 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

302
gradlew vendored
View File

@ -1,79 +1,129 @@
#!/usr/bin/env bash
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn ( ) {
warn () {
echo "$*"
}
} >&2
die ( ) {
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -82,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@ -90,75 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

53
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@ -8,20 +24,23 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -45,34 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

View File

@ -1,38 +1,43 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-allopen'
apply plugin: 'com.google.devtools.ksp'
apply plugin: 'kotlin-parcelize'
dependencies {
api 'com.squareup.okhttp3:okhttp:3.12.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
api 'com.gitlab.ownclouders:dav4android:oc_support_1.0.1'
}
api 'com.squareup.okhttp3:okhttp:4.6.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$orgJetbrainsKotlin"
api 'com.gitlab.ownclouders:dav4android:oc_support_2.1.5'
api 'com.github.AppDevNext.Logcat:LogcatCore:2.2.2'
allOpen {
// allows mocking for classes w/o directly opening them for release builds
annotation 'com.owncloud.android.lib.testing.OpenClass'
// Moshi
implementation("com.squareup.moshi:moshi-kotlin:$comSquareupMoshi") {
exclude module: "kotlin-reflect"
}
implementation 'org.apache.commons:commons-lang3:3.12.0'
ksp "com.squareup.moshi:moshi-kotlin-codegen:$comSquareupMoshi"
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.10'
debugImplementation 'com.facebook.stetho:stetho-okhttp3:1.6.0'
}
android {
compileSdkVersion 28
compileSdkVersion 33
defaultConfig {
minSdkVersion 19
targetSdkVersion 28
versionCode = 10000200
versionName = "1.0.2"
minSdkVersion 23
targetSdkVersion 33
}
lintOptions {
lint {
abortOnError false
ignoreWarnings true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
testOptions {
unitTests {
includeAndroidResources = true
}
}
namespace 'com.owncloud.android.lib'
}

View File

@ -0,0 +1,30 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.owncloud.android.lib.common.http
import com.facebook.stetho.okhttp3.StethoInterceptor
object DebugInterceptorFactory {
fun getInterceptor() = StethoInterceptor()
}

View File

@ -1,31 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.owncloud.android.lib.testing
/**
* This annotation allows us to open some classes for mocking purposes while they are final in
* release builds.
*/
@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class OpenClass
/**
* Annotate a class with [OpenForTesting] if you want it to be extendable in debug builds.
*/
@OpenClass
@Target(AnnotationTarget.CLASS)
annotation class OpenForTesting

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- ownCloud Android Library is available under MIT license
Copyright (C) 2016 ownCloud GmbH.
Copyright (C) 2023 ownCloud GmbH.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -23,16 +23,8 @@
-->
<manifest package="com.owncloud.android.lib"
xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- USE_CREDENTIALS, MANAGE_ACCOUNTS and AUTHENTICATE_ACCOUNTS are needed for API < 23.
In API >= 23 the do not exist anymore -->
<uses-permission
android:name="android.permission.MANAGE_ACCOUNTS"
android:maxSdkVersion="22" />
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

View File

@ -0,0 +1,221 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common
import android.accounts.AccountManager
import android.accounts.AccountsException
import android.content.Context
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials
import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.files.CheckPathExistenceRemoteOperation
import com.owncloud.android.lib.resources.status.GetRemoteStatusOperation
import com.owncloud.android.lib.resources.status.RemoteServerInfo
import org.apache.commons.lang3.exception.ExceptionUtils
import timber.log.Timber
import java.io.IOException
/**
* ConnectionValidator
*
* @author Christian Schabesberger
*/
class ConnectionValidator(
val context: Context,
private val clearCookiesOnValidation: Boolean
) {
fun validate(baseClient: OwnCloudClient, singleSessionManager: SingleSessionManager, context: Context): Boolean {
try {
var validationRetryCount = 0
val client = OwnCloudClient(baseClient.baseUri, null, false, singleSessionManager, context)
if (clearCookiesOnValidation) {
client.clearCookies()
} else {
client.cookiesForBaseUri = baseClient.cookiesForBaseUri
}
client.account = baseClient.account
client.credentials = baseClient.credentials
while (validationRetryCount < VALIDATION_RETRY_COUNT) {
Timber.d("validationRetryCount %d", validationRetryCount)
var successCounter = 0
var failCounter = 0
client.setFollowRedirects(true)
if (isOwnCloudStatusOk(client)) {
successCounter++
} else {
failCounter++
}
// Skip the part where we try to check if we can access the parts where we have to be logged in... if we are not logged in
if (baseClient.credentials !is OwnCloudAnonymousCredentials) {
client.setFollowRedirects(false)
val contentReply = canAccessRootFolder(client)
if (contentReply.httpCode == HttpConstants.HTTP_OK) {
if (contentReply.data == true) { //if data is true it means that the content reply was ok
successCounter++
} else {
failCounter++
}
} else {
failCounter++
if (contentReply.httpCode == HttpConstants.HTTP_UNAUTHORIZED) {
checkUnauthorizedAccess(client, singleSessionManager, contentReply.httpCode)
}
}
}
if (successCounter >= failCounter) {
baseClient.credentials = client.credentials
baseClient.cookiesForBaseUri = client.cookiesForBaseUri
return true
}
validationRetryCount++
}
Timber.d("Could not authenticate or get valid data from owncloud")
} catch (e: Exception) {
Timber.d(ExceptionUtils.getStackTrace(e))
}
return false
}
private fun isOwnCloudStatusOk(client: OwnCloudClient): Boolean {
val reply = getOwnCloudStatus(client)
// dont check status code. It currently relais on the broken redirect code of the owncloud client
// TODO: Use okhttp redirect and add this check again
// return reply.httpCode == HttpConstants.HTTP_OK &&
return !reply.isException &&
reply.data != null
}
private fun getOwnCloudStatus(client: OwnCloudClient): RemoteOperationResult<RemoteServerInfo> {
val remoteStatusOperation = GetRemoteStatusOperation()
return remoteStatusOperation.execute(client)
}
private fun canAccessRootFolder(client: OwnCloudClient): RemoteOperationResult<Boolean> {
val checkPathExistenceRemoteOperation = CheckPathExistenceRemoteOperation("/", true)
return checkPathExistenceRemoteOperation.execute(client)
}
/**
* Determines if credentials should be invalidated according the to the HTTPS status
* of a network request just performed.
*
* @param httpStatusCode Result of the last request ran with the 'credentials' belows.
* @return 'True' if credentials should and might be invalidated, 'false' if shouldn't or
* cannot be invalidated with the given arguments.
*/
private fun shouldInvalidateAccountCredentials(credentials: OwnCloudCredentials, account: OwnCloudAccount, httpStatusCode: Int): Boolean {
var shouldInvalidateAccountCredentials = httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED
shouldInvalidateAccountCredentials = shouldInvalidateAccountCredentials and // real credentials
(credentials !is OwnCloudAnonymousCredentials)
// test if have all the needed to effectively invalidate ...
shouldInvalidateAccountCredentials =
shouldInvalidateAccountCredentials and (account.savedAccount != null)
Timber.d(
"""Received error: $httpStatusCode,
account: ${account.name}
credentials are real: ${credentials !is OwnCloudAnonymousCredentials},
so we need to invalidate credentials for account ${account.name} : $shouldInvalidateAccountCredentials"""
)
return shouldInvalidateAccountCredentials
}
/**
* Invalidates credentials stored for the given account in the system [AccountManager] and in
* current [SingleSessionManager.getDefaultSingleton] instance.
*
*
* [.shouldInvalidateAccountCredentials] should be called first.
*
*/
private fun invalidateAccountCredentials(account: OwnCloudAccount, credentials: OwnCloudCredentials) {
Timber.i("Invalidating account credentials for account $account")
val am = AccountManager.get(context)
am.invalidateAuthToken(
account.savedAccount.type,
credentials.authToken
)
am.clearPassword(account.savedAccount) // being strict, only needed for Basic Auth credentials
}
/**
* Checks the status code of an execution and decides if should be repeated with fresh credentials.
*
*
* Invalidates current credentials if the request failed as anauthorized.
*
*
* Refresh current credentials if possible, and marks a retry.
*
* @return
*/
private fun checkUnauthorizedAccess(client: OwnCloudClient, singleSessionManager: SingleSessionManager, status: Int): Boolean {
var credentialsWereRefreshed = false
val account = client.account
val credentials = account.credentials
if (shouldInvalidateAccountCredentials(credentials, account, status)) {
invalidateAccountCredentials(account, credentials)
if (credentials.authTokenCanBeRefreshed()) {
try {
// This command does the actual refresh
Timber.i("Trying to refresh auth token for account $account")
account.loadCredentials(context)
// if mAccount.getCredentials().length() == 0 --> refresh failed
client.credentials = account.credentials
credentialsWereRefreshed = true
} catch (e: AccountsException) {
Timber.e(
e, "Error while trying to refresh auth token for %s\ntrace: %s",
account.savedAccount.name,
ExceptionUtils.getStackTrace(e)
)
} catch (e: IOException) {
Timber.e(
e, "Error while trying to refresh auth token for %s\ntrace: %s",
account.savedAccount.name,
ExceptionUtils.getStackTrace(e)
)
}
if (!credentialsWereRefreshed) {
// if credentials are not refreshed, client must be removed
// from the OwnCloudClientManager to prevent it is reused once and again
Timber.w("Credentials were not refreshed, client will be removed from the Session Manager to prevent using it over and over")
singleSessionManager.removeClientFor(account)
}
}
// else: onExecute will finish with status 401
}
return credentialsWereRefreshed
}
companion object {
private const val VALIDATION_RETRY_COUNT = 3
}
}

View File

@ -1,63 +0,0 @@
package com.owncloud.android.lib.common;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.io.IOException;
/**
* Dynamic implementation of {@link OwnCloudClientManager}.
* <p>
* Wraps instances of {@link SingleSessionManager} and {@link SimpleFactoryManager} and delegates on one
* or the other depending on the known version of the server corresponding to the {@link OwnCloudAccount}
*
* @author David A. Velasco
*/
public class DynamicSessionManager implements OwnCloudClientManager {
private SimpleFactoryManager mSimpleFactoryManager = new SimpleFactoryManager();
private SingleSessionManager mSingleSessionManager = new SingleSessionManager();
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context)
throws AccountUtils.AccountNotFoundException,
OperationCanceledException, AuthenticatorException, IOException {
OwnCloudVersion ownCloudVersion = null;
if (account.getSavedAccount() != null) {
ownCloudVersion = AccountUtils.getServerVersionForAccount(
account.getSavedAccount(), context
);
}
if (ownCloudVersion != null && ownCloudVersion.isSessionMonitoringSupported()) {
return mSingleSessionManager.getClientFor(account, context);
} else {
return mSimpleFactoryManager.getClientFor(account, context);
}
}
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
OwnCloudClient clientRemovedFromFactoryManager = mSimpleFactoryManager.removeClientFor(account);
OwnCloudClient clientRemovedFromSingleSessionManager = mSingleSessionManager.removeClientFor(account);
if (clientRemovedFromSingleSessionManager != null) {
return clientRemovedFromSingleSessionManager;
} else {
return clientRemovedFromFactoryManager;
}
// clientRemoved and clientRemoved2 should not be != null at the same time
}
@Override
public void saveAllClients(Context context, String accountType) {
mSimpleFactoryManager.saveAllClients(context, accountType);
mSingleSessionManager.saveAllClients(context, accountType);
}
}

View File

@ -107,13 +107,11 @@ public class OwnCloudAccount {
* Method for deferred load of account attributes from AccountManager
*
* @param context
* @throws AccountNotFoundException
* @throws AuthenticatorException
* @throws IOException
* @throws OperationCanceledException
*/
public void loadCredentials(Context context) throws AuthenticatorException,
IOException, OperationCanceledException {
public void loadCredentials(Context context) throws AuthenticatorException, IOException, OperationCanceledException {
if (context == null) {
throw new IllegalArgumentException("Parameter 'context' cannot be null");
@ -151,5 +149,4 @@ public class OwnCloudAccount {
return null;
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@ -25,11 +25,9 @@
package com.owncloud.android.lib.common;
import android.accounts.AccountManager;
import android.accounts.AccountsException;
import android.content.Context;
import android.net.Uri;
import at.bitfire.dav4android.exception.HttpException;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
@ -37,190 +35,130 @@ import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import com.owncloud.android.lib.common.network.RedirectionPath;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.common.utils.RandomUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import okhttp3.Cookie;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import timber.log.Timber;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import static com.owncloud.android.lib.common.http.HttpConstants.OC_X_REQUEST_ID;
import static com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER;
import static com.owncloud.android.lib.common.http.HttpConstants.HTTP_MOVED_PERMANENTLY;
public class OwnCloudClient extends HttpClient {
public static final String WEBDAV_FILES_PATH_4_0 = "/remote.php/dav/files/";
public static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
public static final String STATUS_PATH = "/status.php";
public static final String FILES_WEB_PATH = "/index.php/apps/files";
private static final String WEBDAV_UPLOADS_PATH_4_0 = "/remote.php/dav/uploads/";
private static final int MAX_RETRY_COUNT = 2;
private static final String TAG = OwnCloudClient.class.getSimpleName();
private static final int MAX_REDIRECTIONS_COUNT = 3;
private static final int MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS = 1;
private static byte[] sExhaustBuffer = new byte[1024];
private static int sIntanceCounter = 0;
private OwnCloudCredentials mCredentials = null;
private int mInstanceNumber;
private Uri mBaseUri;
private OwnCloudVersion mVersion = null;
private OwnCloudAccount mAccount;
private final ConnectionValidator mConnectionValidator;
private Object mRequestMutex = new Object();
/**
* {@link @OwnCloudClientManager} holding a reference to this object and delivering it to callers; might be
* NULL
*/
private OwnCloudClientManager mOwnCloudClientManager = null;
// If set to true a mutex will be used to prevent parallel execution of the execute() method
// if false the execute() method can be called even though the mutex is already aquired.
// This is used for the ConnectionValidator, which has to be able to execute OperationsWhile all "normal" operations net
// to be set on hold.
private final Boolean mSynchronizeRequests;
private String mRedirectedLocation;
private boolean mFollowRedirects;
private SingleSessionManager mSingleSessionManager = null;
private boolean mFollowRedirects = false;
public OwnCloudClient(Uri baseUri,
ConnectionValidator connectionValidator,
boolean synchronizeRequests,
SingleSessionManager singleSessionManager,
Context context) {
super(context);
public OwnCloudClient(Uri baseUri) {
if (baseUri == null) {
throw new IllegalArgumentException("Parameter 'baseUri' cannot be NULL");
}
mBaseUri = baseUri;
mSynchronizeRequests = synchronizeRequests;
mSingleSessionManager = singleSessionManager;
mInstanceNumber = sIntanceCounter++;
Log_OC.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient");
Timber.d("#" + mInstanceNumber + "Creating OwnCloudClient");
clearCredentials();
clearCookies();
mConnectionValidator = connectionValidator;
}
public void clearCredentials() {
if (!(mCredentials instanceof OwnCloudAnonymousCredentials)) {
mCredentials = OwnCloudCredentialsFactory.getAnonymousCredentials();
}
mCredentials.applyTo(this);
}
public void applyCredentials() {
mCredentials.applyTo(this);
}
public int executeHttpMethod(HttpBaseMethod method) throws Exception {
boolean repeatWithFreshCredentials;
if (mSynchronizeRequests) {
synchronized (mRequestMutex) {
return saveExecuteHttpMethod(method);
}
} else {
return saveExecuteHttpMethod(method);
}
}
private int saveExecuteHttpMethod(HttpBaseMethod method) throws Exception {
int repeatCounter = 0;
int status;
if (mFollowRedirects) {
method.setFollowRedirects(true);
}
boolean retry;
do {
setRequestId(method);
status = method.execute();
checkFirstRedirection(method);
if (mFollowRedirects && !isIdPRedirection()) {
status = followRedirection(method).getLastStatus();
}
repeatWithFreshCredentials = checkUnauthorizedAccess(status, repeatCounter);
if (repeatWithFreshCredentials) {
repeatCounter++;
}
} while (repeatWithFreshCredentials);
return status;
}
private void checkFirstRedirection(HttpBaseMethod method) {
final String location = method.getResponseHeader(HttpConstants.LOCATION_HEADER_LOWER);
if (location != null && !location.isEmpty()) {
mRedirectedLocation = location;
}
}
private int executeRedirectedHttpMethod(HttpBaseMethod method) throws Exception {
boolean repeatWithFreshCredentials;
int repeatCounter = 0;
int status;
do {
setRequestId(method);
status = method.execute();
repeatWithFreshCredentials = checkUnauthorizedAccess(status, repeatCounter);
if (repeatWithFreshCredentials) {
repeatCounter++;
}
} while (repeatWithFreshCredentials);
return status;
}
private void setRequestId(HttpBaseMethod method) {
// Clean previous request id. This is a bit hacky but is the only way to add request headers in WebDAV
// methods by using Dav4Android
deleteHeaderForAllRequests(OC_X_REQUEST_ID);
retry = false;
String requestId = RandomUtils.generateRandomUUID();
// Header to allow tracing requests in apache and ownCloud logs
addHeaderForAllRequests(OC_X_REQUEST_ID, requestId);
Log_OC.d(TAG, "Executing " + method.getClass().getSimpleName() + " in request with id " + requestId);
Timber.d("Executing in request with id %s", requestId);
method.setRequestHeader(HttpConstants.OC_X_REQUEST_ID, requestId);
method.setRequestHeader(HttpConstants.USER_AGENT_HEADER, SingleSessionManager.getUserAgent());
method.setRequestHeader(HttpConstants.ACCEPT_LANGUAGE_HEADER, Locale.getDefault().getLanguage());
method.setRequestHeader(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY);
if (mCredentials.getHeaderAuth() != null && !mCredentials.getHeaderAuth().isEmpty()) {
method.setRequestHeader(AUTHORIZATION_HEADER, mCredentials.getHeaderAuth());
}
public RedirectionPath followRedirection(HttpBaseMethod method) throws Exception {
int redirectionsCount = 0;
int status = method.getStatusCode();
RedirectionPath redirectionPath = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT);
status = method.execute(this);
while (redirectionsCount < MAX_REDIRECTIONS_COUNT &&
(status == HttpConstants.HTTP_MOVED_PERMANENTLY ||
status == HttpConstants.HTTP_MOVED_TEMPORARILY ||
status == HttpConstants.HTTP_TEMPORARY_REDIRECT)
) {
final String location = method.getResponseHeader(HttpConstants.LOCATION_HEADER) != null
? method.getResponseHeader(HttpConstants.LOCATION_HEADER)
: method.getResponseHeader(HttpConstants.LOCATION_HEADER_LOWER);
if (location != null) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Location to redirect: " + location);
redirectionPath.addLocation(location);
// Release the connection to avoid reach the max number of connections per host
// due to it will be set a different url
exhaustResponse(method.getResponseBodyAsStream());
method.setUrl(HttpUrl.parse(location));
final String destination = method.getRequestHeader("Destination") != null
? method.getRequestHeader("Destination")
: method.getRequestHeader("destination");
if (destination != null) {
final int suffixIndex = location.lastIndexOf(getUserFilesWebDavUri().toString());
final String redirectionBase = location.substring(0, suffixIndex);
final String destinationPath = destination.substring(mBaseUri.toString().length());
method.setRequestHeader("destination", redirectionBase + destinationPath);
if (shouldConnectionValidatorBeCalled(method, status)) {
retry = mConnectionValidator.validate(this, mSingleSessionManager, getContext()); // retry on success fail on no success
} else if (method.getFollowPermanentRedirects() && status == HTTP_MOVED_PERMANENTLY) {
retry = true;
method.setFollowRedirects(true);
}
try {
status = executeRedirectedHttpMethod(method);
} catch (HttpException e) {
if (e.getMessage().contains(Integer.toString(HttpConstants.HTTP_MOVED_TEMPORARILY))) {
status = HttpConstants.HTTP_MOVED_TEMPORARILY;
} else {
throw e;
}
}
redirectionPath.addStatus(status);
redirectionsCount++;
} else {
Log_OC.d(TAG + " #" + mInstanceNumber, "No location to redirect!");
status = HttpConstants.HTTP_NOT_FOUND;
} while (retry && repeatCounter < MAX_RETRY_COUNT);
return status;
}
}
return redirectionPath;
private boolean shouldConnectionValidatorBeCalled(HttpBaseMethod method, int status) {
return mConnectionValidator != null && (
(!(mCredentials instanceof OwnCloudAnonymousCredentials) &&
status == HttpConstants.HTTP_UNAUTHORIZED
) || (!mFollowRedirects &&
!method.getFollowRedirects() &&
status == HttpConstants.HTTP_MOVED_TEMPORARILY
)
);
}
/**
@ -231,14 +169,10 @@ public class OwnCloudClient extends HttpClient {
public void exhaustResponse(InputStream responseBodyAsStream) {
if (responseBodyAsStream != null) {
try {
while (responseBodyAsStream.read(sExhaustBuffer) >= 0) {
;
}
responseBodyAsStream.close();
} catch (IOException io) {
Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" +
" will be IGNORED", io);
Timber.e(io, "Unexpected exception while exhausting not interesting HTTP response; will be IGNORED");
}
}
}
@ -248,7 +182,7 @@ public class OwnCloudClient extends HttpClient {
}
public Uri getUserFilesWebDavUri() {
return mCredentials instanceof OwnCloudAnonymousCredentials
return (mCredentials instanceof OwnCloudAnonymousCredentials || mAccount == null)
? Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0)
: Uri.parse(mBaseUri + WEBDAV_FILES_PATH_4_0 + AccountUtils.getUserId(
mAccount.getSavedAccount(), getContext()
@ -290,70 +224,21 @@ public class OwnCloudClient extends HttpClient {
public void setCredentials(OwnCloudCredentials credentials) {
if (credentials != null) {
mCredentials = credentials;
mCredentials.applyTo(this);
} else {
clearCredentials();
}
}
private void logCookie(Cookie cookie) {
Log_OC.d(TAG, "Cookie name: " + cookie.name());
Log_OC.d(TAG, " value: " + cookie.value());
Log_OC.d(TAG, " domain: " + cookie.domain());
Log_OC.d(TAG, " path: " + cookie.path());
Log_OC.d(TAG, " expiryDate: " + cookie.expiresAt());
Log_OC.d(TAG, " secure: " + cookie.secure());
}
private void logCookiesAtRequest(Headers headers, String when) {
int counter = 0;
for (final String cookieHeader : headers.toMultimap().get("cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Cookies at request (" + when + ") (" + counter++ + "): "
+ cookieHeader);
}
if (counter == 0) {
Log_OC.d(TAG + " #" + mInstanceNumber, "No cookie at request before");
}
}
private void logSetCookiesAtResponse(Headers headers) {
int counter = 0;
for (final String cookieHeader : headers.toMultimap().get("set-cookie")) {
Log_OC.d(TAG + " #" + mInstanceNumber,
"Set-Cookie (" + counter++ + "): " + cookieHeader);
}
if (counter == 0) {
Log_OC.d(TAG + " #" + mInstanceNumber, "No set-cookie");
}
}
public String getCookiesString() {
StringBuilder cookiesString = new StringBuilder();
List<Cookie> cookieList = getCookiesFromUrl(HttpUrl.parse(mBaseUri.toString()));
if (cookieList != null) {
for (Cookie cookie : cookieList) {
cookiesString.append(cookie.toString()).append(";");
}
}
return cookiesString.toString();
}
public void setCookiesForCurrentAccount(List<Cookie> cookies) {
public void setCookiesForBaseUri(List<Cookie> cookies) {
getOkHttpClient().cookieJar().saveFromResponse(
HttpUrl.parse(getAccount().getBaseUri().toString()),
HttpUrl.parse(mBaseUri.toString()),
cookies
);
}
public OwnCloudVersion getOwnCloudVersion() {
return mVersion;
}
public void setOwnCloudVersion(OwnCloudVersion version) {
mVersion = version;
public List<Cookie> getCookiesForBaseUri() {
return getOkHttpClient().cookieJar().loadForRequest(
HttpUrl.parse(mBaseUri.toString()));
}
public OwnCloudAccount getAccount() {
@ -364,116 +249,6 @@ public class OwnCloudClient extends HttpClient {
this.mAccount = account;
}
/**
* Checks the status code of an execution and decides if should be repeated with fresh credentials.
* <p>
* Invalidates current credentials if the request failed as anauthorized.
* <p>
* Refresh current credentials if possible, and marks a retry.
*
* @param status
* @param repeatCounter
* @return
*/
private boolean checkUnauthorizedAccess(int status, int repeatCounter) {
boolean credentialsWereRefreshed = false;
if (shouldInvalidateAccountCredentials(status)) {
boolean invalidated = invalidateAccountCredentials();
if (invalidated) {
if (getCredentials().authTokenCanBeRefreshed() &&
repeatCounter < MAX_REPEAT_COUNT_WITH_FRESH_CREDENTIALS) {
try {
mAccount.loadCredentials(getContext());
// if mAccount.getCredentials().length() == 0 --> refresh failed
setCredentials(mAccount.getCredentials());
credentialsWereRefreshed = true;
} catch (AccountsException | IOException e) {
Log_OC.e(
TAG,
"Error while trying to refresh auth token for " + mAccount.getSavedAccount().name,
e
);
}
}
if (!credentialsWereRefreshed && mOwnCloudClientManager != null) {
// if credentials are not refreshed, client must be removed
// from the OwnCloudClientManager to prevent it is reused once and again
mOwnCloudClientManager.removeClientFor(mAccount);
}
}
// else: onExecute will finish with status 401
}
return credentialsWereRefreshed;
}
/**
* Determines if credentials should be invalidated according the to the HTTPS status
* of a network request just performed.
*
* @param httpStatusCode Result of the last request ran with the 'credentials' belows.
* @return 'True' if credentials should and might be invalidated, 'false' if shouldn't or
* cannot be invalidated with the given arguments.
*/
private boolean shouldInvalidateAccountCredentials(int httpStatusCode) {
boolean should = (httpStatusCode == HttpConstants.HTTP_UNAUTHORIZED || isIdPRedirection()); // invalid credentials
should &= (mCredentials != null && // real credentials
!(mCredentials instanceof OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials));
// test if have all the needed to effectively invalidate ...
should &= (mAccount != null && mAccount.getSavedAccount() != null && getContext() != null);
return should;
}
/**
* Invalidates credentials stored for the given account in the system {@link AccountManager} and in
* current {@link OwnCloudClientManagerFactory#getDefaultSingleton()} instance.
* <p>
* {@link #shouldInvalidateAccountCredentials(int)} should be called first.
*
* @return 'True' if invalidation was successful, 'false' otherwise.
*/
private boolean invalidateAccountCredentials() {
AccountManager am = AccountManager.get(getContext());
am.invalidateAuthToken(
mAccount.getSavedAccount().type,
mCredentials.getAuthToken()
);
am.clearPassword(mAccount.getSavedAccount()); // being strict, only needed for Basic Auth credentials
return true;
}
public OwnCloudClientManager getOwnCloudClientManager() {
return mOwnCloudClientManager;
}
void setOwnCloudClientManager(OwnCloudClientManager clientManager) {
mOwnCloudClientManager = clientManager;
}
/**
* Check if the redirection is to an identity provider such as SAML or wayf
*
* @return true if the redirection location includes SAML or wayf, false otherwise
*/
private boolean isIdPRedirection() {
return (mRedirectedLocation != null &&
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
}
public boolean followRedirects() {
return mFollowRedirects;
}
public void setFollowRedirects(boolean followRedirects) {
this.mFollowRedirects = followRedirects;
}

View File

@ -1,162 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import java.io.IOException;
public class OwnCloudClientFactory {
final private static String TAG = OwnCloudClientFactory.class.getSimpleName();
/**
* Creates a OwnCloudClient setup for an ownCloud account
* <p>
* Do not call this method from the main thread.
*
* @param account The ownCloud account
* @param appContext Android application context
* @param currentActivity Caller {@link Activity}
* @return A OwnCloudClient object ready to be used
* @throws AuthenticatorException If the authenticator failed to get the authorization
* token for the account.
* @throws OperationCanceledException If the authenticator operation was cancelled while
* getting the authorization token for the account.
* @throws IOException If there was some I/O error while getting the
* authorization token for the account.
* @throws AccountNotFoundException If 'account' is unknown for the AccountManager
*/
public static OwnCloudClient createOwnCloudClient(Account account, Context appContext,
Activity currentActivity)
throws OperationCanceledException, AuthenticatorException, IOException,
AccountNotFoundException {
Uri baseUri = Uri.parse(AccountUtils.getBaseUrlForAccount(appContext, account));
AccountManager am = AccountManager.get(appContext);
// TODO avoid calling to getUserData here
boolean isOauth2 =
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2) != null;
boolean isSamlSso =
am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO) != null;
OwnCloudClient client = createOwnCloudClient(baseUri, appContext, !isSamlSso);
String username = AccountUtils.getUsernameForAccount(account);
if (isOauth2) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
null,
currentActivity,
null,
null);
Bundle result = future.getResult();
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (accessToken == null) {
throw new AuthenticatorException("WTF!");
}
client.setCredentials(
OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken)
);
} else if (isSamlSso) { // TODO avoid a call to getUserData here
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
null,
currentActivity,
null,
null);
Bundle result = future.getResult();
String accessToken = result.getString(AccountManager.KEY_AUTHTOKEN);
if (accessToken == null) {
throw new AuthenticatorException("WTF!");
}
client.setCredentials(
OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken)
);
} else {
AccountManagerFuture<Bundle> future = am.getAuthToken(
account,
AccountTypeUtils.getAuthTokenTypePass(account.type),
null,
currentActivity,
null,
null
);
Bundle result = future.getResult();
String password = result.getString(AccountManager.KEY_AUTHTOKEN);
OwnCloudVersion version = AccountUtils.getServerVersionForAccount(account, appContext);
client.setCredentials(
OwnCloudCredentialsFactory.newBasicCredentials(
username,
password,
(version != null && version.isPreemptiveAuthenticationPreferred())
)
);
}
// Restore cookies
AccountUtils.restoreCookies(account, client, appContext);
return client;
}
/**
* Creates a OwnCloudClient to access a URL and sets the desired parameters for ownCloud
* client connections.
*
* @param uri URL to the ownCloud server; BASE ENTRY POINT, not WebDavPATH
* @param context Android context where the OwnCloudClient is being created.
* @return A OwnCloudClient object ready to be used
*/
public static OwnCloudClient createOwnCloudClient(Uri uri, Context context,
boolean followRedirects) {
OwnCloudClient client = new OwnCloudClient(uri);
client.setFollowRedirects(followRedirects);
client.setContext(context);
return client;
}
}

View File

@ -1,54 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import java.io.IOException;
/**
* Manager to create and reuse OwnCloudClient instances to access remote OC servers.
*
* @author David A. Velasco
* @author masensio
* @author Christian Schabesberger
*/
public interface OwnCloudClientManager {
OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws AccountNotFoundException,
OperationCanceledException, AuthenticatorException,
IOException;
OwnCloudClient removeClientFor(OwnCloudAccount account);
void saveAllClients(Context context, String accountType)
throws AccountNotFoundException, AuthenticatorException,
IOException, OperationCanceledException;
}

View File

@ -1,101 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common;
public class OwnCloudClientManagerFactory {
private static Policy sDefaultPolicy = Policy.ALWAYS_NEW_CLIENT;
private static OwnCloudClientManager sDefaultSingleton;
private static String sUserAgent;
public static OwnCloudClientManager newDefaultOwnCloudClientManager() {
return newOwnCloudClientManager(sDefaultPolicy);
}
public static OwnCloudClientManager newOwnCloudClientManager(Policy policy) {
switch (policy) {
case ALWAYS_NEW_CLIENT:
return new SimpleFactoryManager();
case SINGLE_SESSION_PER_ACCOUNT:
return new SingleSessionManager();
case SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING:
return new DynamicSessionManager();
default:
throw new IllegalArgumentException("Unknown policy");
}
}
public static OwnCloudClientManager getDefaultSingleton() {
if (sDefaultSingleton == null) {
sDefaultSingleton = newDefaultOwnCloudClientManager();
}
return sDefaultSingleton;
}
public static Policy getDefaultPolicy() {
return sDefaultPolicy;
}
public static void setDefaultPolicy(Policy policy) {
if (policy == null) {
throw new IllegalArgumentException("Default policy cannot be NULL");
}
if (defaultSingletonMustBeUpdated(policy)) {
sDefaultSingleton = null;
}
sDefaultPolicy = policy;
}
public static String getUserAgent() {
return sUserAgent;
}
public static void setUserAgent(String userAgent) {
sUserAgent = userAgent;
}
private static boolean defaultSingletonMustBeUpdated(Policy policy) {
if (sDefaultSingleton == null) {
return false;
}
if (policy == Policy.ALWAYS_NEW_CLIENT &&
!(sDefaultSingleton instanceof SimpleFactoryManager)) {
return true;
}
if (policy == Policy.SINGLE_SESSION_PER_ACCOUNT &&
!(sDefaultSingleton instanceof SingleSessionManager)) {
return true;
}
return false;
}
public static enum Policy {
ALWAYS_NEW_CLIENT,
SINGLE_SESSION_PER_ACCOUNT,
SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING
}
}

View File

@ -1,79 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.io.IOException;
public class SimpleFactoryManager implements OwnCloudClientManager {
private static final String TAG = SimpleFactoryManager.class.getSimpleName();
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws
OperationCanceledException, AuthenticatorException, IOException {
Log_OC.d(TAG, "getClientFor(OwnCloudAccount ... : ");
OwnCloudClient client = OwnCloudClientFactory.createOwnCloudClient(
account.getBaseUri(),
context.getApplicationContext(),
true);
Log_OC.v(TAG, " new client {" +
(account.getName() != null ?
account.getName() :
AccountUtils.buildAccountName(account.getBaseUri(), "")
) + ", " + client.hashCode() + "}");
if (account.getCredentials() == null) {
account.loadCredentials(context);
}
client.setCredentials(account.getCredentials());
client.setAccount(account);
client.setContext(context);
client.setOwnCloudClientManager(this);
return client;
}
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
// nothing to do - not taking care of tracking instances!
return null;
}
@Override
public void saveAllClients(Context context, String accountType) {
// nothing to do - not taking care of tracking instances!
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,51 +24,78 @@
package com.owncloud.android.lib.common;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Context;
import android.net.Uri;
import android.util.Log;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.authentication.OwnCloudSamlSsoCredentials;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import timber.log.Timber;
import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Implementation of {@link OwnCloudClientManager}
* <p>
* TODO check multithreading safety
*
* @author David A. Velasco
* @author masensio
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class SingleSessionManager implements OwnCloudClientManager {
public class SingleSessionManager {
private static final String TAG = SingleSessionManager.class.getSimpleName();
private static SingleSessionManager sDefaultSingleton;
private static String sUserAgent;
private static ConnectionValidator sConnectionValidator;
private ConcurrentMap<String, OwnCloudClient> mClientsWithKnownUsername =
new ConcurrentHashMap<>();
private ConcurrentMap<String, OwnCloudClient> mClientsWithKnownUsername = new ConcurrentHashMap<>();
private ConcurrentMap<String, OwnCloudClient> mClientsWithUnknownUsername = new ConcurrentHashMap<>();
private ConcurrentMap<String, OwnCloudClient> mClientsWithUnknownUsername =
new ConcurrentHashMap<>();
public static SingleSessionManager getDefaultSingleton() {
if (sDefaultSingleton == null) {
sDefaultSingleton = new SingleSessionManager();
}
return sDefaultSingleton;
}
@Override
public OwnCloudClient getClientFor(OwnCloudAccount account, Context context) throws OperationCanceledException,
public static void setConnectionValidator(ConnectionValidator connectionValidator) {
sConnectionValidator = connectionValidator;
}
public static ConnectionValidator getConnectionValidator() {
return sConnectionValidator;
}
public static String getUserAgent() {
return sUserAgent;
}
public static void setUserAgent(String userAgent) {
sUserAgent = userAgent;
}
private static OwnCloudClient createOwnCloudClient(Uri uri,
Context context,
ConnectionValidator connectionValidator,
SingleSessionManager singleSessionManager) {
OwnCloudClient client = new OwnCloudClient(uri, connectionValidator, true, singleSessionManager, context);
return client;
}
public OwnCloudClient getClientFor(OwnCloudAccount account,
Context context) throws OperationCanceledException,
AuthenticatorException, IOException {
return getClientFor(account, context, getConnectionValidator());
}
public OwnCloudClient getClientFor(OwnCloudAccount account,
Context context,
ConnectionValidator connectionValidator) throws OperationCanceledException,
AuthenticatorException, IOException {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "getClientFor starting ");
}
Timber.d("getClientFor starting ");
if (account == null) {
throw new IllegalArgumentException("Cannot get an OwnCloudClient for a null account");
}
@ -76,9 +103,7 @@ public class SingleSessionManager implements OwnCloudClientManager {
OwnCloudClient client = null;
String accountName = account.getName();
String sessionName = account.getCredentials() == null ? "" :
AccountUtils.buildAccountName(
account.getBaseUri(),
account.getCredentials().getAuthToken());
AccountUtils.buildAccountName(account.getBaseUri(), account.getCredentials().getAuthToken());
if (accountName != null) {
client = mClientsWithKnownUsername.get(accountName);
@ -88,77 +113,79 @@ public class SingleSessionManager implements OwnCloudClientManager {
if (accountName != null) {
client = mClientsWithUnknownUsername.remove(sessionName);
if (client != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "reusing client for session " + sessionName);
}
Timber.v("reusing client for session %s", sessionName);
mClientsWithKnownUsername.put(accountName, client);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "moved client to account " + accountName);
}
Timber.v("moved client to account %s", accountName);
}
} else {
client = mClientsWithUnknownUsername.get(sessionName);
}
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "reusing client for account " + accountName);
Timber.v("reusing client for account %s", accountName);
if (client.getAccount() != null &&
client.getAccount().getCredentials() != null &&
(client.getAccount().getCredentials().getAuthToken() == null || client.getAccount().getCredentials().getAuthToken().isEmpty())
) {
Timber.i("Client " + client.getAccount().getName() + " needs to refresh credentials");
//the next two lines are a hack because okHttpclient is used as a singleton instead of being an
//injected instance that can be deleted when required
client.clearCookies();
client.clearCredentials();
client.setAccount(account);
account.loadCredentials(context);
client.setCredentials(account.getCredentials());
Timber.i("Client " + account.getName() + " with credentials size" + client.getAccount().getCredentials().getAuthToken().length());
}
reusingKnown = true;
}
if (client == null) {
// no client to reuse - create a new one
client = OwnCloudClientFactory.createOwnCloudClient(
client = createOwnCloudClient(
account.getBaseUri(),
context.getApplicationContext(),
true); // TODO remove dependency on OwnCloudClientFactory
context,
connectionValidator,
this); // TODO remove dependency on OwnCloudClientFactory
//the next two lines are a hack because okHttpclient is used as a singleton instead of being an
//injected instance that can be deleted when required
client.clearCookies();
client.clearCredentials();
client.setAccount(account);
client.setContext(context);
client.setOwnCloudClientManager(this);
account.loadCredentials(context);
client.setCredentials(account.getCredentials());
if (client.getCredentials() instanceof OwnCloudSamlSsoCredentials) {
client.disableAutomaticCookiesHandling();
}
if (accountName != null) {
mClientsWithKnownUsername.put(accountName, client);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "new client for account " + accountName);
}
Timber.v("new client for account %s", accountName);
} else {
mClientsWithUnknownUsername.put(sessionName, client);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "new client for session " + sessionName);
}
Timber.v("new client for session %s", sessionName);
}
} else {
if (!reusingKnown && Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "reusing client for session " + sessionName);
if (!reusingKnown) {
Timber.v("reusing client for session %s", sessionName);
}
keepCredentialsUpdated(client);
keepCookiesUpdated(context, account, client);
keepUriUpdated(account, client);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "getClientFor finishing ");
}
Timber.d("getClientFor finishing ");
return client;
}
@Override
public OwnCloudClient removeClientFor(OwnCloudAccount account) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "removeClientFor starting ");
}
public void removeClientFor(OwnCloudAccount account) {
Timber.d("removeClientFor starting ");
if (account == null) {
return null;
return;
}
OwnCloudClient client;
@ -166,62 +193,25 @@ public class SingleSessionManager implements OwnCloudClientManager {
if (accountName != null) {
client = mClientsWithKnownUsername.remove(accountName);
if (client != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "Removed client for account " + accountName);
}
return client;
Timber.v("Removed client for account %s", accountName);
return;
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log_OC.v(TAG, "No client tracked for account " + accountName);
}
Timber.v("No client tracked for account %s", accountName);
}
}
mClientsWithUnknownUsername.clear();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "removeClientFor finishing ");
}
return null;
Timber.d("removeClientFor finishing ");
}
@Override
public void saveAllClients(Context context, String accountType) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "Saving sessions... ");
}
Iterator<String> accountNames = mClientsWithKnownUsername.keySet().iterator();
String accountName;
Account account;
while (accountNames.hasNext()) {
accountName = accountNames.next();
account = new Account(accountName, accountType);
AccountUtils.saveClient(
mClientsWithKnownUsername.get(accountName),
account,
context);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log_OC.d(TAG, "All sessions saved");
}
}
private void keepCredentialsUpdated(OwnCloudClient reusedClient) {
reusedClient.applyCredentials();
}
private void keepCookiesUpdated(Context context, OwnCloudAccount account, OwnCloudClient reusedClient) {
AccountManager am = AccountManager.get(context.getApplicationContext());
if (am != null && account.getSavedAccount() != null) {
String recentCookies = am.getUserData(account.getSavedAccount(), AccountUtils.Constants.KEY_COOKIES);
String previousCookies = reusedClient.getCookiesString();
if (recentCookies != null && previousCookies != "" && !recentCookies.equals(previousCookies)) {
AccountUtils.restoreCookies(account.getSavedAccount(), reusedClient, context);
}
public void refreshCredentialsForAccount(String accountName, OwnCloudCredentials credentials) {
OwnCloudClient ownCloudClient = mClientsWithKnownUsername.get(accountName);
if (ownCloudClient == null) {
return;
}
ownCloudClient.setCredentials(credentials);
mClientsWithKnownUsername.replace(accountName, ownCloudClient);
}
// this method is just a patch; we need to distinguish accounts in the same host but

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -41,9 +41,4 @@ public class AccountTypeUtils {
public static String getAuthTokenTypeRefreshToken(String accountType) {
return accountType + ".oauth2.refresh_token";
}
public static String getAuthTokenTypeSamlSessionCookie(String accountType) {
return accountType + ".saml.web_sso.session_cookie";
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
* Copyright (C) 2012 Bartek Przybylski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@ -36,19 +36,12 @@ import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.FileUtils;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import okhttp3.Cookie;
import timber.log.Timber;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class AccountUtils {
private static final String TAG = AccountUtils.class.getSimpleName();
/**
* Constructs full url to host and webdav resource basing on host version
*
@ -59,21 +52,9 @@ public class AccountUtils {
*/
public static String getWebDavUrlForAccount(Context context, Account account)
throws AccountNotFoundException {
String webDavUrlForAccount = "";
try {
OwnCloudCredentials ownCloudCredentials = getCredentialsForAccount(context, account);
webDavUrlForAccount = getBaseUrlForAccount(context, account) + OwnCloudClient.WEBDAV_FILES_PATH_4_0
+ ownCloudCredentials.getUsername();
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return webDavUrlForAccount;
return getBaseUrlForAccount(context, account) + OwnCloudClient.WEBDAV_FILES_PATH_4_0
+ AccountUtils.getUserId(account, context);
}
/**
@ -108,31 +89,11 @@ public class AccountUtils {
try {
username = account.name.substring(0, account.name.lastIndexOf('@'));
} catch (Exception e) {
Log_OC.e(TAG, "Couldn't get a username for the given account", e);
Timber.e(e, "Couldn't get a username for the given account");
}
return username;
}
/**
* Get the stored server version corresponding to an OC account.
*
* @param account An OC account
* @param context Application context
* @return Version of the OC server, according to last check
*/
public static OwnCloudVersion getServerVersionForAccount(Account account, Context context) {
AccountManager ama = AccountManager.get(context);
OwnCloudVersion version = null;
try {
String versionString = ama.getUserData(account, Constants.KEY_OC_VERSION);
version = new OwnCloudVersion(versionString);
} catch (Exception e) {
Log_OC.e(TAG, "Couldn't get a the server version for an account", e);
}
return version;
}
/**
* @return
* @throws IOException
@ -146,32 +107,18 @@ public class AccountUtils {
AccountManager am = AccountManager.get(context);
String supportsOAuth2 = am.getUserData(account, AccountUtils.Constants.KEY_SUPPORTS_OAUTH2);
boolean isOauth2 = supportsOAuth2 != null && supportsOAuth2.equals("TRUE");
String supportsSamlSSo = am.getUserData(account,
AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO);
boolean isSamlSso = supportsSamlSSo != null && supportsSamlSSo.equals("TRUE");
boolean isOauth2 = supportsOAuth2 != null && supportsOAuth2.equals(Constants.OAUTH_SUPPORTED_TRUE);
String username = AccountUtils.getUsernameForAccount(account);
OwnCloudVersion version = new OwnCloudVersion(am.getUserData(account, Constants.KEY_OC_VERSION));
if (isOauth2) {
Timber.i("Trying to retrieve credentials for oAuth account" + account.name);
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeAccessToken(account.type),
false);
credentials = OwnCloudCredentialsFactory.newBearerCredentials(username, accessToken);
} else if (isSamlSso) {
String accessToken = am.blockingGetAuthToken(
account,
AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(account.type),
false);
credentials = OwnCloudCredentialsFactory.newSamlSsoCredentials(username, accessToken);
} else {
String password = am.blockingGetAuthToken(
account,
@ -180,8 +127,7 @@ public class AccountUtils {
credentials = OwnCloudCredentialsFactory.newBasicCredentials(
username,
password,
version.isPreemptiveAuthenticationPreferred()
password
);
}
@ -220,67 +166,8 @@ public class AccountUtils {
if (url.contains("://")) {
url = url.substring(serverBaseUrl.toString().indexOf("://") + 3);
}
String accountName = username + "@" + url;
return accountName;
}
public static void saveClient(OwnCloudClient client, Account savedAccount, Context context) {
// Account Manager
AccountManager ac = AccountManager.get(context.getApplicationContext());
if (client != null) {
String cookiesString = client.getCookiesString();
if (!"".equals(cookiesString)) {
ac.setUserData(savedAccount, Constants.KEY_COOKIES, cookiesString);
Log_OC.d(TAG, "Saving Cookies: " + cookiesString);
}
}
}
/**
* Restore the client cookies persisted in an account stored in the system AccountManager.
*
* @param account Stored account.
* @param client Client to restore cookies in.
* @param context Android context used to access the system AccountManager.
*/
public static void restoreCookies(Account account, OwnCloudClient client, Context context) {
if (account == null) {
Log_OC.d(TAG, "Cannot restore cookie for null account");
} else {
Log_OC.d(TAG, "Restoring cookies for " + account.name);
// Account Manager
AccountManager am = AccountManager.get(context.getApplicationContext());
Uri serverUri = (client.getBaseUri() != null) ? client.getBaseUri() : client.getUserFilesWebDavUri();
String cookiesString = am.getUserData(account, Constants.KEY_COOKIES);
if (cookiesString != null) {
String[] rawCookies = cookiesString.split(";");
List<Cookie> cookieList = new ArrayList<>(rawCookies.length);
for (String rawCookie : rawCookies) {
rawCookie = rawCookie.replace(" ", "");
final int equalPos = rawCookie.indexOf('=');
if (equalPos == -1) {
continue;
}
cookieList.add(new Cookie.Builder()
.name(rawCookie.substring(0, equalPos))
.value(rawCookie.substring(equalPos + 1))
.domain(serverUri.getHost())
.path(
serverUri.getPath().equals("")
? FileUtils.PATH_SEPARATOR
: serverUri.getPath()
)
.build());
}
client.setCookiesForCurrentAccount(cookieList);
}
}
return username + "@" + url;
}
public static class AccountNotFoundException extends AccountsException {
@ -303,11 +190,6 @@ public class AccountUtils {
}
public static class Constants {
/**
* Version should be 3 numbers separated by dot so it can be parsed by
* {@link OwnCloudVersion}
*/
public static final String KEY_OC_VERSION = "oc_version";
/**
* Base url should point to owncloud installation without trailing / ie:
* http://server/path or https://owncloud.server
@ -316,15 +198,11 @@ public class AccountUtils {
/**
* Flag signaling if the ownCloud server can be accessed with OAuth2 access tokens.
*/
// TODO Please review this constants, move them out of the library, the rest of OAuth variables are in data layer
public static final String KEY_SUPPORTS_OAUTH2 = "oc_supports_oauth2";
/**
* Flag signaling if the ownCloud server can be accessed with session cookies from SAML-based web single-sign-on.
*/
public static final String KEY_SUPPORTS_SAML_WEB_SSO = "oc_supports_saml_web_sso";
/**
* OC account cookies
*/
public static final String KEY_COOKIES = "oc_account_cookies";
public static final String OAUTH_SUPPORTED_TRUE = "TRUE";
/**
* OC account version
@ -341,10 +219,6 @@ public class AccountUtils {
*/
public static final String KEY_DISPLAY_NAME = "oc_display_name";
/**
* OAuth2 refresh token
**/
public static final String KEY_OAUTH2_REFRESH_TOKEN = "oc_oauth2_refresh_token";
public static final int ACCOUNT_VERSION = 1;
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,16 +23,12 @@
*/
package com.owncloud.android.lib.common.authentication;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
import okhttp3.Credentials;
import okhttp3.internal.Util;
import static java.nio.charset.StandardCharsets.UTF_8;
public class OwnCloudBasicCredentials implements OwnCloudCredentials {
private static final String TAG = OwnCloudCredentials.class.getSimpleName();
private String mUsername;
private String mPassword;
@ -41,21 +37,6 @@ public class OwnCloudBasicCredentials implements OwnCloudCredentials {
mPassword = password != null ? password : "";
}
public OwnCloudBasicCredentials(String username, String password, boolean preemptiveMode) {
mUsername = username != null ? username : "";
mPassword = password != null ? password : "";
}
@Override
public void applyTo(OwnCloudClient client) {
// Clear previous basic credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
HttpClient.addHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER,
Credentials.basic(mUsername, mPassword, Util.UTF_8));
}
@Override
public String getUsername() {
return mUsername;
@ -66,6 +47,11 @@ public class OwnCloudBasicCredentials implements OwnCloudCredentials {
return mPassword;
}
@Override
public String getHeaderAuth() {
return Credentials.basic(mUsername, mPassword, UTF_8);
}
@Override
public boolean authTokenExpires() {
return false;

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,8 +23,6 @@
*/
package com.owncloud.android.lib.common.authentication;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
public class OwnCloudBearerCredentials implements OwnCloudCredentials {
@ -37,16 +35,6 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials {
mAccessToken = accessToken != null ? accessToken : "";
}
@Override
public void applyTo(OwnCloudClient client) {
// Clear previous credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
HttpClient.addHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER,
HttpConstants.BEARER_AUTHORIZATION_KEY + mAccessToken);
}
@Override
public String getUsername() {
// not relevant for authentication, but relevant for informational purposes
@ -58,6 +46,11 @@ public class OwnCloudBearerCredentials implements OwnCloudCredentials {
return mAccessToken;
}
@Override
public String getHeaderAuth() {
return HttpConstants.BEARER_AUTHORIZATION_KEY + mAccessToken;
}
@Override
public boolean authTokenExpires() {
return true;

View File

@ -24,16 +24,14 @@
package com.owncloud.android.lib.common.authentication;
import com.owncloud.android.lib.common.OwnCloudClient;
public interface OwnCloudCredentials {
void applyTo(OwnCloudClient ownCloudClient);
String getUsername();
String getAuthToken();
String getHeaderAuth();
boolean authTokenExpires();
boolean authTokenCanBeRefreshed();

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -24,10 +24,6 @@
package com.owncloud.android.lib.common.authentication;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
public class OwnCloudCredentialsFactory {
public static final String CREDENTIAL_CHARSET = "UTF-8";
@ -38,20 +34,10 @@ public class OwnCloudCredentialsFactory {
return new OwnCloudBasicCredentials(username, password);
}
public static OwnCloudCredentials newBasicCredentials(
String username, String password, boolean preemptiveMode
) {
return new OwnCloudBasicCredentials(username, password, preemptiveMode);
}
public static OwnCloudCredentials newBearerCredentials(String username, String authToken) {
return new OwnCloudBearerCredentials(username, authToken);
}
public static OwnCloudCredentials newSamlSsoCredentials(String username, String sessionCookie) {
return new OwnCloudSamlSsoCredentials(username, sessionCookie);
}
public static final OwnCloudCredentials getAnonymousCredentials() {
if (sAnonymousCredentials == null) {
sAnonymousCredentials = new OwnCloudAnonymousCredentials();
@ -65,14 +51,12 @@ public class OwnCloudCredentialsFactory {
}
@Override
public void applyTo(OwnCloudClient client) {
// Clear previous basic credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
public String getAuthToken() {
return "";
}
@Override
public String getAuthToken() {
public String getHeaderAuth() {
return "";
}

View File

@ -1,70 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.http.HttpClient;
import com.owncloud.android.lib.common.http.HttpConstants;
public class OwnCloudSamlSsoCredentials implements OwnCloudCredentials {
private String mUsername;
private String mSessionCookie;
public OwnCloudSamlSsoCredentials(String username, String sessionCookie) {
mUsername = username != null ? username : "";
mSessionCookie = sessionCookie != null ? sessionCookie : "";
}
@Override
public void applyTo(OwnCloudClient client) {
// Clear previous credentials
HttpClient.deleteHeaderForAllRequests(HttpConstants.AUTHORIZATION_HEADER);
HttpClient.deleteHeaderForAllRequests(HttpConstants.COOKIE_HEADER);
HttpClient.addHeaderForAllRequests(HttpConstants.COOKIE_HEADER, mSessionCookie);
client.setFollowRedirects(false);
}
@Override
public String getUsername() {
// not relevant for authentication, but relevant for informational purposes
return mUsername;
}
@Override
public String getAuthToken() {
return mSessionCookie;
}
@Override
public boolean authTokenExpires() {
return true;
}
@Override
public boolean authTokenCanBeRefreshed() {
return false;
}
}

View File

@ -1,98 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
/**
* @author David A. Velasco
* @author Christian Schabesberger
*/
public class BearerCredentials {
public static final int HASH_SEED = 17;
public static final int HASH_OFFSET = 37;
private String mAccessToken;
/**
* The constructor with the bearer token
*
* @param token The bearer token
*/
public BearerCredentials(String token) {
/*if (token == null) {
throw new IllegalArgumentException("Bearer token may not be null");
}*/
mAccessToken = (token == null) ? "" : token;
}
/**
* Returns the access token
*
* @return The access token
*/
public String getAccessToken() {
return mAccessToken;
}
/**
* Get this object string.
*
* @return The access token
*/
public String toString() {
return mAccessToken;
}
/**
* Does a hash of the access token.
*
* @return The hash code of the access token
*/
public int hashCode() {
return HASH_SEED * HASH_OFFSET + mAccessToken.hashCode();
}
/**
* These credentials are assumed equal if accessToken is the same.
*
* @param o The other object to compare with.
* @return 'True' if the object is equivalent.
*/
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
if (this.getClass().equals(o.getClass())) {
BearerCredentials that = (BearerCredentials) o;
if (mAccessToken.equals(that.mAccessToken)) {
return true;
}
}
return false;
}
}

View File

@ -1,66 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
public class OAuth2ClientConfiguration {
private String mClientId;
private String mClientSecret;
private String mRedirectUri;
public OAuth2ClientConfiguration(String clientId, String clientSecret, String redirectUri) {
mClientId = (clientId == null) ? "" : clientId;
mClientSecret = (clientSecret == null) ? "" : clientSecret;
mRedirectUri = (redirectUri == null) ? "" : redirectUri;
}
public String getClientId() {
return mClientId;
}
public void setClientId(String clientId) {
mClientId = (clientId == null) ? "" : clientId;
}
public String getClientSecret() {
return mClientSecret;
}
public void setClientSecret(String clientSecret) {
mClientSecret = (clientSecret == null) ? "" : clientSecret;
}
public String getRedirectUri() {
return mRedirectUri;
}
public void setRedirectUri(String redirectUri) {
this.mRedirectUri = (redirectUri == null) ? "" : redirectUri;
}
}

View File

@ -1,68 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
/**
* Constant values for OAuth 2 protocol.
* <p>
* Includes required and optional parameter NAMES used in the 'authorization code' grant type.
*/
public class OAuth2Constants {
/// Parameters to send to the Authorization Endpoint
public static final String KEY_RESPONSE_TYPE = "response_type";
public static final String KEY_REDIRECT_URI = "redirect_uri";
public static final String KEY_CLIENT_ID = "client_id";
public static final String KEY_SCOPE = "scope";
public static final String KEY_STATE = "state";
/// Additional parameters to send to the Token Endpoint
public static final String KEY_GRANT_TYPE = "grant_type";
public static final String KEY_CODE = "code";
// Used to get the Access Token using Refresh Token
public static final String OAUTH2_REFRESH_TOKEN_GRANT_TYPE = "refresh_token";
/// Parameters received in an OK response from the Token Endpoint
public static final String KEY_ACCESS_TOKEN = "access_token";
public static final String KEY_TOKEN_TYPE = "token_type";
public static final String KEY_EXPIRES_IN = "expires_in";
public static final String KEY_REFRESH_TOKEN = "refresh_token";
/// Parameters in an ERROR response
public static final String KEY_ERROR = "error";
public static final String KEY_ERROR_DESCRIPTION = "error_description";
public static final String KEY_ERROR_URI = "error_uri";
public static final String VALUE_ERROR_ACCESS_DENIED = "access_denied";
/// Extra not standard
public static final String KEY_USER_ID = "user_id";
/// Depends on oauth2 grant type
public static final String OAUTH2_RESPONSE_TYPE_CODE = "code";
}

View File

@ -1,141 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* @author Christian Schabesberger
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import org.json.JSONObject;
import java.net.URL;
import java.util.Map;
public class OAuth2GetAccessTokenOperation extends RemoteOperation<Map<String, String>> {
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
private String mGrantType;
private String mCode;
private String mClientId;
private String mClientSecret;
private String mRedirectUri;
public OAuth2GetAccessTokenOperation(
String grantType,
String code,
String clientId,
String secretId,
String redirectUri,
String accessTokenEndpointPath
) {
mClientId = clientId;
mClientSecret = secretId;
mRedirectUri = redirectUri;
mGrantType = grantType;
mCode = code;
mAccessTokenEndpointPath =
accessTokenEndpointPath != null ?
accessTokenEndpointPath :
OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH
;
mResponseParser = new OAuth2ResponseParser();
}
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult<Map<String, String>> result = null;
try {
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE, mGrantType)
.addFormDataPart(OAuth2Constants.KEY_CODE, mCode)
.addFormDataPart(OAuth2Constants.KEY_REDIRECT_URI, mRedirectUri)
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.build();
Uri.Builder uriBuilder = client.getBaseUri().buildUpon();
uriBuilder.appendEncodedPath(mAccessTokenEndpointPath);
final PostMethod postMethod = new PostMethod(new URL(
client.getBaseUri().buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build()
.toString()));
postMethod.setRequestBody(requestBody);
OwnCloudCredentials oauthCredentials =
new OwnCloudBasicCredentials(mClientId, mClientSecret);
OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials);
client.executeHttpMethod(postMethod);
switchClientCredentials(oldCredentials);
String response = postMethod.getResponseBodyAsString();
if (response != null && response.length() > 0) {
JSONObject tokenJson = new JSONObject(response);
Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
if (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null) {
result = new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR);
} else {
result = new RemoteOperationResult<>(ResultCode.OK);
result.setData(accessTokenResult);
}
} else {
result = new RemoteOperationResult<>(ResultCode.OK);
client.exhaustResponse(postMethod.getResponseBodyAsStream());
}
} catch (Exception e) {
result = new RemoteOperationResult<>(e);
}
return result;
}
private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) {
OwnCloudCredentials previousCredentials = getClient().getCredentials();
getClient().setCredentials(newCredentials);
return previousCredentials;
}
}

View File

@ -1,65 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
public interface OAuth2Provider {
/**
* {@link OAuth2RequestBuilder} implementation for this provider.
*
* @return {@link OAuth2RequestBuilder} implementation.
*/
OAuth2RequestBuilder getOperationBuilder();
/**
* Configuration of the client that is using this {@link OAuth2Provider}
* return Configuration of the client that is usinng this {@link OAuth2Provider}
*/
OAuth2ClientConfiguration getClientConfiguration();
/**
* Set configuration of the client that will use this {@link OAuth2Provider}
*
* @param oAuth2ClientConfiguration Configuration of the client that will use this {@link OAuth2Provider}
*/
void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration);
/**
* base URI to authorization server.
*
* @return Base URL to authorization server.
*/
String getAuthorizationServerUri();
/**
* Set base URI to authorization server.
*
* @param authorizationServerUri Set base URL to authorization server.
*/
void setAuthorizationServerUri(String authorizationServerUri);
}

View File

@ -1,121 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import java.util.HashMap;
import java.util.Map;
public class OAuth2ProvidersRegistry {
private Map<String, OAuth2Provider> mProviders = new HashMap<>();
private OAuth2Provider mDefaultProvider = null;
private OAuth2ProvidersRegistry() {
}
/**
* Singleton accesor.
*
* @return Singleton isntance of {@link OAuth2ProvidersRegistry}
*/
public static OAuth2ProvidersRegistry getInstance() {
return LazyHolder.INSTANCE;
}
/**
* Register an {@link OAuth2Provider} with the name passed as parameter.
*
* @param name Name to bind 'oAuthProvider' in the registry.
* @param oAuth2Provider An {@link OAuth2Provider} instance to keep in the registry.
* @throws IllegalArgumentException if 'name' or 'oAuthProvider' are null.
*/
public void registerProvider(String name, OAuth2Provider oAuth2Provider) {
if (name == null) {
throw new IllegalArgumentException("Name must not be NULL");
}
if (oAuth2Provider == null) {
throw new IllegalArgumentException("oAuth2Provider must not be NULL");
}
mProviders.put(name, oAuth2Provider);
if (mProviders.size() == 1) {
mDefaultProvider = oAuth2Provider;
}
}
public OAuth2Provider unregisterProvider(String name) {
OAuth2Provider unregisteredProvider = mProviders.remove(name);
if (mProviders.size() == 0) {
mDefaultProvider = null;
} else if (unregisteredProvider != null && unregisteredProvider == mDefaultProvider) {
mDefaultProvider = mProviders.values().iterator().next();
}
return unregisteredProvider;
}
/**
* Get default {@link OAuth2Provider}.
*
* @return Default provider, or NULL if there is no provider.
*/
public OAuth2Provider getProvider() {
return mDefaultProvider;
}
/**
* Get {@link OAuth2Provider} registered with the name passed as parameter.
*
* @param name Name used to register the desired {@link OAuth2Provider}
* @return {@link OAuth2Provider} registered with the name 'name'
*/
public OAuth2Provider getProvider(String name) {
return mProviders.get(name);
}
/**
* Sets the {@link OAuth2Provider} registered with the name passed as parameter as the default provider
*
* @param name Name used to register the {@link OAuth2Provider} to set as default.
* @return {@link OAuth2Provider} set as default, or NULL if no provider was registered with 'name'.
*/
public OAuth2Provider setDefaultProvider(String name) {
OAuth2Provider toDefault = mProviders.get(name);
if (toDefault != null) {
mDefaultProvider = toDefault;
}
return toDefault;
}
/**
* See https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom
*/
private static class LazyHolder {
private static final OAuth2ProvidersRegistry INSTANCE = new OAuth2ProvidersRegistry();
}
}

View File

@ -1,74 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.util.HashMap;
import java.util.Map;
public class OAuth2QueryParser {
private static final String TAG = OAuth2QueryParser.class.getName();
private Map<String, String> mOAuth2ParsedAuthorizationResponse;
public OAuth2QueryParser() {
mOAuth2ParsedAuthorizationResponse = new HashMap<>();
}
public Map<String, String> parse(String query) {
mOAuth2ParsedAuthorizationResponse.clear();
if (query != null) {
String[] pairs = query.split("&");
int i = 0;
String key = "";
String value;
while (pairs.length > i) {
int j = 0;
String[] part = pairs[i].split("=");
while (part.length > j) {
String p = part[j];
if (j == 0) {
key = p;
} else if (j == 1) {
value = p;
mOAuth2ParsedAuthorizationResponse.put(key, value);
}
Log_OC.v(TAG, "[" + i + "," + j + "] = " + p);
j++;
}
i++;
}
}
return mOAuth2ParsedAuthorizationResponse;
}
}

View File

@ -1,127 +0,0 @@
/**
* ownCloud Android client application
*
* @author David González Verdugo
* @author Christian Schabesberger
* <p>
* Copyright (C) 2019 ownCloud GmbH.
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p>
* 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.authentication.OwnCloudBasicCredentials;
import com.owncloud.android.lib.common.authentication.OwnCloudCredentials;
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import org.json.JSONObject;
import java.net.URL;
import java.util.Map;
public class OAuth2RefreshAccessTokenOperation extends RemoteOperation<Map<String, String>> {
private static final String TAG = OAuth2RefreshAccessTokenOperation.class.getSimpleName();
private final String mAccessTokenEndpointPath;
private final OAuth2ResponseParser mResponseParser;
private String mClientId;
private String mClientSecret;
private String mRefreshToken;
public OAuth2RefreshAccessTokenOperation(
String clientId,
String secretId,
String refreshToken,
String accessTokenEndpointPath
) {
mClientId = clientId;
mClientSecret = secretId;
mRefreshToken = refreshToken;
mAccessTokenEndpointPath =
accessTokenEndpointPath != null ?
accessTokenEndpointPath :
OwnCloudOAuth2Provider.ACCESS_TOKEN_ENDPOINT_PATH
;
mResponseParser = new OAuth2ResponseParser();
}
@Override
protected RemoteOperationResult<Map<String, String>> run(OwnCloudClient client) {
try {
final RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(OAuth2Constants.KEY_GRANT_TYPE,
OAuth2GrantType.REFRESH_TOKEN.getValue())
.addFormDataPart(OAuth2Constants.KEY_CLIENT_ID, mClientId)
.addFormDataPart(OAuth2Constants.KEY_REFRESH_TOKEN, mRefreshToken)
.build();
Uri.Builder uriBuilder = client.getBaseUri().buildUpon();
uriBuilder.appendEncodedPath(mAccessTokenEndpointPath);
final PostMethod postMethod = new PostMethod(new URL(
client.getBaseUri().buildUpon()
.appendEncodedPath(mAccessTokenEndpointPath)
.build()
.toString()));
postMethod.setRequestBody(requestBody);
final OwnCloudCredentials oauthCredentials = new OwnCloudBasicCredentials(mClientId, mClientSecret);
final OwnCloudCredentials oldCredentials = switchClientCredentials(oauthCredentials);
client.executeHttpMethod(postMethod);
switchClientCredentials(oldCredentials);
final String responseData = postMethod.getResponseBodyAsString();
Log_OC.d(TAG, "OAUTH2: raw response from POST TOKEN: " + responseData);
if (responseData != null && responseData.length() > 0) {
final JSONObject tokenJson = new JSONObject(responseData);
final Map<String, String> accessTokenResult =
mResponseParser.parseAccessTokenResult(tokenJson);
final RemoteOperationResult<Map<String, String>> result = new RemoteOperationResult<>(ResultCode.OK);
result.setData(accessTokenResult);
return (accessTokenResult.get(OAuth2Constants.KEY_ERROR) != null ||
accessTokenResult.get(OAuth2Constants.KEY_ACCESS_TOKEN) == null)
? new RemoteOperationResult<>(ResultCode.OAUTH2_ERROR)
: result;
} else {
return new RemoteOperationResult<>(postMethod);
}
} catch (Exception e) {
return new RemoteOperationResult<>(e);
}
}
private OwnCloudCredentials switchClientCredentials(OwnCloudCredentials newCredentials) {
OwnCloudCredentials previousCredentials = getClient().getCredentials();
getClient().setCredentials(newCredentials);
return previousCredentials;
}
}

View File

@ -1,75 +0,0 @@
/**
* ownCloud Android client application
*
* @author David A. Velasco
* <p>
* Copyright (C) 2017 ownCloud GmbH.
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
* <p>
* 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.lib.common.authentication.oauth;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
class OAuth2ResponseParser {
Map<String, String> parseAccessTokenResult(JSONObject tokenJson) throws JSONException {
Map<String, String> resultTokenMap = new HashMap<>();
if (tokenJson.has(OAuth2Constants.KEY_ACCESS_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_ACCESS_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_ACCESS_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_TOKEN_TYPE)) {
resultTokenMap.put(OAuth2Constants.KEY_TOKEN_TYPE, tokenJson.
getString(OAuth2Constants.KEY_TOKEN_TYPE));
}
if (tokenJson.has(OAuth2Constants.KEY_EXPIRES_IN)) {
resultTokenMap.put(OAuth2Constants.KEY_EXPIRES_IN, tokenJson.
getString(OAuth2Constants.KEY_EXPIRES_IN));
}
if (tokenJson.has(OAuth2Constants.KEY_REFRESH_TOKEN)) {
resultTokenMap.put(OAuth2Constants.KEY_REFRESH_TOKEN, tokenJson.
getString(OAuth2Constants.KEY_REFRESH_TOKEN));
}
if (tokenJson.has(OAuth2Constants.KEY_SCOPE)) {
resultTokenMap.put(OAuth2Constants.KEY_SCOPE, tokenJson.
getString(OAuth2Constants.KEY_SCOPE));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR, tokenJson.
getString(OAuth2Constants.KEY_ERROR));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_DESCRIPTION)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_DESCRIPTION, tokenJson.
getString(OAuth2Constants.KEY_ERROR_DESCRIPTION));
}
if (tokenJson.has(OAuth2Constants.KEY_ERROR_URI)) {
resultTokenMap.put(OAuth2Constants.KEY_ERROR_URI, tokenJson.
getString(OAuth2Constants.KEY_ERROR_URI));
}
if (tokenJson.has(OAuth2Constants.KEY_USER_ID)) { // not standard
resultTokenMap.put(OAuth2Constants.KEY_USER_ID, tokenJson.
getString(OAuth2Constants.KEY_USER_ID));
}
return resultTokenMap;
}
}

View File

@ -1,94 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import com.owncloud.android.lib.common.utils.Log_OC;
public class OwnCloudOAuth2Provider implements OAuth2Provider {
public static final String NAME = OAuth2Provider.class.getName();
public static final String ACCESS_TOKEN_ENDPOINT_PATH = "index.php/apps/oauth2/api/v1/token";
private static final String AUTHORIZATION_CODE_ENDPOINT_PATH = "index.php/apps/oauth2/authorize";
private String mAuthorizationServerUrl = "";
private String mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH;
private String mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH;
private OAuth2ClientConfiguration mClientConfiguration;
@Override
public OAuth2RequestBuilder getOperationBuilder() {
return new OwnCloudOAuth2RequestBuilder(this);
}
@Override
public OAuth2ClientConfiguration getClientConfiguration() {
return mClientConfiguration;
}
@Override
public void setClientConfiguration(OAuth2ClientConfiguration oAuth2ClientConfiguration) {
mClientConfiguration = oAuth2ClientConfiguration;
}
@Override
public String getAuthorizationServerUri() {
return mAuthorizationServerUrl;
}
@Override
public void setAuthorizationServerUri(String authorizationServerUri) {
mAuthorizationServerUrl = authorizationServerUri;
}
public String getAccessTokenEndpointPath() {
return mAccessTokenEndpointPath;
}
public void setAccessTokenEndpointPath(String accessTokenEndpointPath) {
if (accessTokenEndpointPath == null || accessTokenEndpointPath.length() <= 0) {
Log_OC.w(NAME, "Setting invalid access token endpoint path, going on with default");
mAccessTokenEndpointPath = ACCESS_TOKEN_ENDPOINT_PATH;
} else {
mAccessTokenEndpointPath = accessTokenEndpointPath;
}
}
public String getAuthorizationCodeEndpointPath() {
return mAuthorizationCodeEndpointPath;
}
public void setAuthorizationCodeEndpointPath(String authorizationCodeEndpointPath) {
if (authorizationCodeEndpointPath == null || authorizationCodeEndpointPath.length() <= 0) {
Log_OC.w(NAME, "Setting invalid authorization code endpoint path, going on with default");
mAuthorizationCodeEndpointPath = AUTHORIZATION_CODE_ENDPOINT_PATH;
} else {
mAuthorizationCodeEndpointPath = authorizationCodeEndpointPath;
}
}
}

View File

@ -1,156 +0,0 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.authentication.oauth;
import android.net.Uri;
import com.owncloud.android.lib.common.operations.RemoteOperation;
public class OwnCloudOAuth2RequestBuilder implements OAuth2RequestBuilder {
private OwnCloudOAuth2Provider mOAuth2Provider;
private OAuthRequest mRequest;
private OAuth2GrantType mGrantType = OAuth2GrantType.AUTHORIZATION_CODE;
private String mCode;
private String mRefreshToken;
public OwnCloudOAuth2RequestBuilder(OwnCloudOAuth2Provider ownCloudOAuth2Provider) {
mOAuth2Provider = ownCloudOAuth2Provider;
}
@Override
public void setRequest(OAuthRequest request) {
mRequest = request;
}
@Override
public void setGrantType(OAuth2GrantType grantType) {
mGrantType = grantType;
}
@Override
public void setAuthorizationCode(String code) {
mCode = code;
}
@Override
public void setRefreshToken(String refreshToken) {
mRefreshToken = refreshToken;
}
@Override
public RemoteOperation buildOperation() {
if (mGrantType != OAuth2GrantType.AUTHORIZATION_CODE &&
mGrantType != OAuth2GrantType.REFRESH_TOKEN) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " and " +
OAuth2GrantType.REFRESH_TOKEN + " are supported"
);
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
switch (mRequest) {
case CREATE_ACCESS_TOKEN:
return new OAuth2GetAccessTokenOperation(
mGrantType.getValue(),
mCode,
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
clientConfiguration.getRedirectUri(),
mOAuth2Provider.getAccessTokenEndpointPath()
);
case REFRESH_ACCESS_TOKEN:
return new OAuth2RefreshAccessTokenOperation(
clientConfiguration.getClientId(),
clientConfiguration.getClientSecret(),
mRefreshToken,
mOAuth2Provider.getAccessTokenEndpointPath()
);
default:
throw new UnsupportedOperationException(
"Unsupported request"
);
}
}
@Override
public String buildUri() {
if (OAuth2GrantType.AUTHORIZATION_CODE != mGrantType) {
throw new UnsupportedOperationException(
"Unsupported grant type. Only " +
OAuth2GrantType.AUTHORIZATION_CODE.getValue() + " is supported by this provider"
);
}
OAuth2ClientConfiguration clientConfiguration = mOAuth2Provider.getClientConfiguration();
Uri uri;
Uri.Builder uriBuilder;
switch (mRequest) {
case GET_AUTHORIZATION_CODE:
uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri());
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAuthorizationCodeEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
);
uri = uriBuilder.build();
return uri.toString();
case CREATE_ACCESS_TOKEN:
uri = Uri.parse(mOAuth2Provider.getAuthorizationServerUri());
uriBuilder = uri.buildUpon();
uriBuilder.appendEncodedPath(mOAuth2Provider.getAccessTokenEndpointPath());
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_RESPONSE_TYPE, OAuth2Constants.OAUTH2_RESPONSE_TYPE_CODE
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_REDIRECT_URI, clientConfiguration.getRedirectUri()
);
uriBuilder.appendQueryParameter(
OAuth2Constants.KEY_CLIENT_ID, clientConfiguration.getClientId()
);
uri = uriBuilder.build();
return uri.toString();
default:
throw new UnsupportedOperationException(
"Unsupported request"
);
}
}
}

View File

@ -0,0 +1,62 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2021 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
class CookieJarImpl(
private val cookieStore: HashMap<String, List<Cookie>>
) : CookieJar {
fun containsCookieWithName(cookies: List<Cookie>, name: String): Boolean {
for (cookie: Cookie in cookies) {
if (cookie.name == name) {
return true
}
}
return false
}
fun getUpdatedCookies(oldCookies: List<Cookie>, newCookies: List<Cookie>): List<Cookie> {
val updatedList = ArrayList<Cookie>(newCookies)
for (oldCookie: Cookie in oldCookies) {
if (!containsCookieWithName(updatedList, oldCookie.name)) {
updatedList.add(oldCookie)
}
}
return updatedList
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
// Avoid duplicated cookies but update
val currentCookies: List<Cookie> = cookieStore[url.host] ?: ArrayList()
val updatedCookies: List<Cookie> = getUpdatedCookies(currentCookies, cookies)
cookieStore[url.host] = updatedCookies
}
override fun loadForRequest(url: HttpUrl) =
cookieStore[url.host] ?: ArrayList()
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -22,23 +22,10 @@
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav;
package com.owncloud.android.lib.common.http
import java.io.IOException;
import java.net.URL;
import okhttp3.Interceptor
public class PutMethod extends HttpMethod {
public PutMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
.put(mRequestBody)
.build();
return super.onExecute();
}
class DummyInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain) = chain.proceed(chain.request())
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -26,30 +26,24 @@ package com.owncloud.android.lib.common.http;
import android.content.Context;
import android.os.Build;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.http.interceptors.HttpInterceptor;
import com.owncloud.android.lib.common.http.interceptors.RequestHeaderInterceptor;
import com.owncloud.android.lib.common.network.AdvancedX509TrustManager;
import com.owncloud.android.lib.common.network.NetworkUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.TlsVersion;
import timber.log.Timber;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
@ -57,144 +51,97 @@ import java.util.concurrent.TimeUnit;
*
* @author David González Verdugo
*/
public class HttpClient {
private static final String TAG = HttpClient.class.toString();
private Context mContext;
private HashMap<String, List<Cookie>> mCookieStore = new HashMap<>();
private LogInterceptor mLogInterceptor = new LogInterceptor();
private static OkHttpClient sOkHttpClient;
private static HttpInterceptor sOkHttpInterceptor;
private static Context sContext;
private static HashMap<String, List<Cookie>> sCookieStore = new HashMap<>();
private OkHttpClient mOkHttpClient = null;
public static OkHttpClient getOkHttpClient() {
if (sOkHttpClient == null) {
protected HttpClient(Context context) {
if (context == null) {
Timber.e("Context may not be NULL!");
throw new NullPointerException("Context may not be NULL!");
}
mContext = context;
}
public OkHttpClient getOkHttpClient() {
if (mOkHttpClient == null) {
try {
final X509TrustManager trustManager = new AdvancedX509TrustManager(
NetworkUtils.getKnownServersStore(sContext));
NetworkUtils.getKnownServersStore(mContext));
SSLContext sslContext;
final SSLContext sslContext = buildSSLContext();
sslContext.init(null, new TrustManager[]{trustManager}, null);
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// Automatic cookie handling, NOT PERSISTENT
final CookieJar cookieJar = new CookieJarImpl(mCookieStore);
mOkHttpClient = buildNewOkHttpClient(sslSocketFactory, trustManager, cookieJar);
} catch (NoSuchAlgorithmException nsae) {
Timber.e(nsae, "Could not setup SSL system.");
throw new RuntimeException("Could not setup okHttp client.", nsae);
} catch (Exception e) {
Timber.e(e, "Could not setup okHttp client.");
throw new RuntimeException("Could not setup okHttp client.", e);
}
}
return mOkHttpClient;
}
private SSLContext buildSSLContext() throws NoSuchAlgorithmException {
try {
sslContext = SSLContext.getInstance("TLSv1.2");
return SSLContext.getInstance(TlsVersion.TLS_1_3.javaName());
} catch (NoSuchAlgorithmException tlsv13Exception) {
try {
Timber.w("TLSv1.3 is not supported in this device; falling through TLSv1.2");
return SSLContext.getInstance(TlsVersion.TLS_1_2.javaName());
} catch (NoSuchAlgorithmException tlsv12Exception) {
try {
Log_OC.w(TAG, "TLSv1.2 is not supported in this device; falling through TLSv1.1");
sslContext = SSLContext.getInstance("TLSv1.1");
Timber.w("TLSv1.2 is not supported in this device; falling through TLSv1.1");
return SSLContext.getInstance(TlsVersion.TLS_1_1.javaName());
} catch (NoSuchAlgorithmException tlsv11Exception) {
Log_OC.w(TAG, "TLSv1.1 is not supported in this device; falling through TLSv1.0");
sslContext = SSLContext.getInstance("TLSv1");
Timber.w("TLSv1.1 is not supported in this device; falling through TLSv1.0");
return SSLContext.getInstance(TlsVersion.TLS_1_0.javaName());
// should be available in any device; see reference of supported protocols in
// http://developer.android.com/reference/javax/net/ssl/SSLSocket.html
}
}
sslContext.init(null, new TrustManager[]{trustManager}, null);
SSLSocketFactory sslSocketFactory;
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
// TLS v1.2 is disabled by default in API 19, use custom SSLSocketFactory to enable it
sslSocketFactory = new TLSSocketFactory(sslContext.getSocketFactory());
} else {
sslSocketFactory = sslContext.getSocketFactory();
}
}
// Automatic cookie handling, NOT PERSISTENT
CookieJar cookieJar = new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// Avoid duplicated cookies
Set<Cookie> nonDuplicatedCookiesSet = new HashSet<>();
nonDuplicatedCookiesSet.addAll(cookies);
List<Cookie> nonDuplicatedCookiesList = new ArrayList<>();
nonDuplicatedCookiesList.addAll(nonDuplicatedCookiesSet);
sCookieStore.put(url.host(), nonDuplicatedCookiesList);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = sCookieStore.get(url.host());
return cookies != null ? cookies : new ArrayList<>();
}
};
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.addInterceptor(getOkHttpInterceptor())
.protocols(Arrays.asList(Protocol.HTTP_1_1))
private OkHttpClient buildNewOkHttpClient(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager,
CookieJar cookieJar) {
return new OkHttpClient.Builder()
.addNetworkInterceptor(getLogInterceptor())
.addNetworkInterceptor(DebugInterceptorFactory.INSTANCE.getInterceptor())
.protocols(Collections.singletonList(Protocol.HTTP_1_1))
.readTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
.connectTimeout(HttpConstants.DEFAULT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.followRedirects(false)
.sslSocketFactory(sslSocketFactory, trustManager)
.hostnameVerifier((asdf, usdf) -> true)
.cookieJar(cookieJar);
// TODO: Not verifying the hostname against certificate. ask owncloud security human if this is ok.
//.hostnameVerifier(new BrowserCompatHostnameVerifier());
sOkHttpClient = clientBuilder.build();
} catch (Exception e) {
Log_OC.e(TAG, "Could not setup SSL system.", e);
}
}
return sOkHttpClient;
}
private static HttpInterceptor getOkHttpInterceptor() {
if (sOkHttpInterceptor == null) {
sOkHttpInterceptor = new HttpInterceptor();
addHeaderForAllRequests(HttpConstants.USER_AGENT_HEADER, OwnCloudClientManagerFactory.getUserAgent());
addHeaderForAllRequests(HttpConstants.PARAM_SINGLE_COOKIE_HEADER, "true");
addHeaderForAllRequests(HttpConstants.ACCEPT_ENCODING_HEADER, HttpConstants.ACCEPT_ENCODING_IDENTITY);
}
return sOkHttpInterceptor;
}
/**
* Add header that will be included for all the requests from now on
*
* @param headerName
* @param headerValue
*/
public static void addHeaderForAllRequests(String headerName, String headerValue) {
getOkHttpInterceptor()
.addRequestInterceptor(
new RequestHeaderInterceptor(headerName, headerValue)
);
}
public static void deleteHeaderForAllRequests(String headerName) {
getOkHttpInterceptor().deleteRequestHeaderInterceptor(headerName);
.cookieJar(cookieJar)
.build();
}
public Context getContext() {
return sContext;
return mContext;
}
public static void setContext(Context context) {
sContext = context;
}
public void disableAutomaticCookiesHandling() {
OkHttpClient.Builder clientBuilder = getOkHttpClient().newBuilder();
clientBuilder.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
// DO NOTHING
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
return new ArrayList<>();
}
});
sOkHttpClient = clientBuilder.build();
public LogInterceptor getLogInterceptor() {
return mLogInterceptor;
}
public List<Cookie> getCookiesFromUrl(HttpUrl httpUrl) {
return sCookieStore.get(httpUrl.host());
return mCookieStore.get(httpUrl.host());
}
public void clearCookies() {
sCookieStore.clear();
mCookieStore.clear();
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -40,16 +40,44 @@ public class HttpConstants {
public static final String IF_MATCH_HEADER = "If-Match";
public static final String IF_NONE_MATCH_HEADER = "If-None-Match";
public static final String CONTENT_TYPE_HEADER = "Content-Type";
public static final String ACCEPT_LANGUAGE_HEADER = "Accept-Language";
public static final String CONTENT_LENGTH_HEADER = "Content-Length";
public static final String OC_TOTAL_LENGTH_HEADER = "OC-Total-Length";
public static final String OC_X_OC_MTIME_HEADER = "X-OC-Mtime";
public static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header";
public static final String OC_X_REQUEST_ID = "X-Request-ID";
public static final String LOCATION_HEADER = "Location";
public static final String LOCATION_HEADER_LOWER = "location";
public static final String CONTENT_TYPE_URLENCODED_UTF8 = "application/x-www-form-urlencoded; charset=utf-8";
public static final String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
public static final String ACCEPT_ENCODING_IDENTITY = "identity";
public static final String OC_FILE_REMOTE_ID = "OC-FileId";
// OAuth
public static final String OAUTH_HEADER_AUTHORIZATION_CODE = "code";
public static final String OAUTH_HEADER_GRANT_TYPE = "grant_type";
public static final String OAUTH_HEADER_REDIRECT_URI = "redirect_uri";
public static final String OAUTH_HEADER_REFRESH_TOKEN = "refresh_token";
public static final String OAUTH_HEADER_CODE_VERIFIER = "code_verifier";
/***********************************************************************************************************
************************************************ CONTENT TYPES ********************************************
***********************************************************************************************************/
public static final String CONTENT_TYPE_XML = "application/xml";
public static final String CONTENT_TYPE_JSON = "application/json";
public static final String CONTENT_TYPE_WWW_FORM = "application/x-www-form-urlencoded";
/***********************************************************************************************************
************************************************ ARGUMENTS NAMES ********************************************
***********************************************************************************************************/
public static final String PARAM_FORMAT = "format";
/***********************************************************************************************************
************************************************ ARGUMENTS VALUES ********************************************
***********************************************************************************************************/
public static final String VALUE_FORMAT = "json";
/***********************************************************************************************************
************************************************ STATUS CODES *********************************************
@ -157,6 +185,7 @@ public class HttpConstants {
public static final int HTTP_LOCKED = 423;
// 424 Failed Dependency (WebDAV - RFC 2518)
public static final int HTTP_FAILED_DEPENDENCY = 424;
public static final int HTTP_TOO_EARLY = 425;
/**
* 5xx Client Error

View File

@ -0,0 +1,65 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.owncloud.android.lib.common.http
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_JSON
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_WWW_FORM
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_XML
import okhttp3.MediaType
import timber.log.Timber
import java.util.Locale
object LogBuilder {
fun logHttp(
networkPetition: NetworkPetition,
networkNode: NetworkNode,
requestId: String? = "",
description: String
) = Timber.d("[Network, $networkPetition] [$networkNode] [$requestId] $description")
}
enum class NetworkPetition {
REQUEST, RESPONSE;
override fun toString(): String = super.toString().lowercase(Locale.ROOT)
}
enum class NetworkNode {
INFO, HEADER, BODY;
override fun toString(): String = super.toString().lowercase(Locale.ROOT)
}
/**
* Check whether a media type is loggable.
*
* @return true if its type is text, xml, json, or x-www-form-urlencoded.
*/
fun MediaType?.isLoggable(): Boolean =
this?.let { mediaType ->
val mediaTypeString = mediaType.toString()
(mediaType.type == "text" ||
mediaTypeString.contains(CONTENT_TYPE_XML) ||
mediaTypeString.contains(CONTENT_TYPE_JSON) ||
mediaTypeString.contains(CONTENT_TYPE_WWW_FORM))
} ?: false

View File

@ -0,0 +1,179 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http
import com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER
import com.owncloud.android.lib.common.http.HttpConstants.OC_X_REQUEST_ID
import com.owncloud.android.lib.common.http.LogBuilder.logHttp
import com.owncloud.android.lib.common.http.NetworkNode.BODY
import com.owncloud.android.lib.common.http.NetworkNode.HEADER
import com.owncloud.android.lib.common.http.NetworkNode.INFO
import com.owncloud.android.lib.common.http.NetworkPetition.REQUEST
import com.owncloud.android.lib.common.http.NetworkPetition.RESPONSE
import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.RequestBody
import okhttp3.Response
import okhttp3.ResponseBody
import okio.Buffer
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import kotlin.math.max
class LogInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
if (!httpLogsEnabled) {
return chain.proceed(chain.request())
}
val request = chain.request().also {
val requestId = it.headers[OC_X_REQUEST_ID]
logHttp(REQUEST, INFO, requestId, "Method: ${it.method} URL: ${it.url}")
logHeaders(requestId, it.headers, REQUEST)
logRequestBody(requestId, it.body)
}
val response = chain.proceed(request)
return response.also {
val requestId = it.request.headers[OC_X_REQUEST_ID]
logHttp(
RESPONSE,
INFO,
requestId,
"Method: ${request.method} URL: ${request.url} Code: ${it.code} Message: ${it.message}"
)
logHeaders(requestId, it.headers, RESPONSE)
logResponseBody(requestId, it.body)
}
}
private fun logHeaders(requestId: String?, headers: Headers, networkPetition: NetworkPetition) {
headers.forEach { header ->
val headerValue: String = if (header.first.equals(AUTHORIZATION_HEADER, true)) {
"[redacted]"
} else {
header.second
}
logHttp(networkPetition, HEADER, requestId, "${header.first}: $headerValue")
}
}
private fun logRequestBody(requestId: String?, requestBodyParam: RequestBody?) {
requestBodyParam?.let { requestBody ->
if (requestBody.isOneShot()) {
logHttp(REQUEST, BODY, requestId, "One shot body -- Omitted")
return@let
}
if (requestBody.isDuplex()) {
logHttp(REQUEST, BODY, requestId, "Duplex body -- Omitted")
return@let
}
val buffer = Buffer()
requestBody.writeTo(buffer)
val contentType = requestBody.contentType()
val charset: Charset = contentType?.charset(StandardCharsets.UTF_8) ?: StandardCharsets.UTF_8
logHttp(REQUEST, BODY, requestId, "Length: ${requestBody.contentLength()} byte body")
logHttp(REQUEST, BODY, requestId, "Type: ${requestBody.contentType()}")
logHttp(REQUEST, BODY, requestId, "--> Body start for request")
if (contentType.isLoggable()) {
if (requestBody.contentLength() < LIMIT_BODY_LOG) {
logHttp(REQUEST, BODY, requestId, buffer.readString(charset))
} else {
logHttp(REQUEST, BODY, requestId, buffer.readString(LIMIT_BODY_LOG, charset))
}
logHttp(
REQUEST,
BODY,
requestId,
"<-- Body end for request -- Omitted: ${max(0, requestBody.contentLength() - LIMIT_BODY_LOG)} bytes"
)
} else {
logHttp(
REQUEST,
BODY,
requestId,
"<-- Body end for request -- Binary -- Omitted: ${requestBody.contentLength()} bytes"
)
}
} ?: logHttp(REQUEST, BODY, requestId, "Empty body")
}
private fun logResponseBody(requestId: String?, responseBodyParam: ResponseBody?) {
responseBodyParam?.let { responseBody ->
val contentType = responseBody.contentType()
val charset: Charset = contentType?.charset(StandardCharsets.UTF_8) ?: StandardCharsets.UTF_8
logHttp(RESPONSE, BODY, requestId, "Length: ${responseBody.contentLength()} byte body")
logHttp(RESPONSE, BODY, requestId, "Type: ${responseBody.contentType()}")
logHttp(RESPONSE, BODY, requestId, "--> Body start for response")
val source = responseBody.source()
source.request(LIMIT_BODY_LOG)
val buffer = source.buffer
if (contentType.isLoggable()) {
if (responseBody.contentLength() < LIMIT_BODY_LOG) {
logHttp(RESPONSE, BODY, requestId, buffer.clone().readString(charset))
} else {
logHttp(RESPONSE, BODY, requestId, buffer.clone().readString(LIMIT_BODY_LOG, charset))
}
logHttp(
RESPONSE,
BODY,
requestId,
"<-- Body end for response -- Omitted: ${
max(
0,
responseBody.contentLength() - LIMIT_BODY_LOG
)
} bytes"
)
} else {
logHttp(
RESPONSE,
BODY,
requestId,
"<-- Body end for response -- Binary -- Omitted: ${responseBody.contentLength()} bytes"
)
}
} ?: logHttp(RESPONSE, BODY, requestId, "Empty body")
}
companion object {
var httpLogsEnabled: Boolean = false
private const val LIMIT_BODY_LOG: Long = 1024
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -74,8 +74,8 @@ public class TLSSocketFactory extends SSLSocketFactory {
}
private Socket enableTLSOnSocket(Socket socket) {
if(socket != null && (socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
if((socket instanceof SSLSocket)) {
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2", "TLSv1.3"});
}
return socket;
}

View File

@ -1,110 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.interceptors;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.ArrayList;
import java.util.ListIterator;
/**
* Http interceptor to use multiple interceptors in the same {@link okhttp3.OkHttpClient} instance
*
* @author David González Verdugo
*/
public class HttpInterceptor implements Interceptor {
private final ArrayList<RequestInterceptor> mRequestInterceptors = new ArrayList<>();
private final ArrayList<ResponseInterceptor> mResponseInterceptors = new ArrayList<>();
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
for (RequestInterceptor interceptor : mRequestInterceptors) {
request = interceptor.intercept(request);
}
Response response = chain.proceed(request);
for (ResponseInterceptor interceptor : mResponseInterceptors) {
response = interceptor.intercept(response);
}
return response;
}
public HttpInterceptor addRequestInterceptor(RequestInterceptor requestInterceptor) {
mRequestInterceptors.add(requestInterceptor);
return this;
}
public HttpInterceptor addResponseInterceptor(ResponseInterceptor responseInterceptor) {
mResponseInterceptors.add(responseInterceptor);
return this;
}
public ArrayList<RequestInterceptor> getRequestInterceptors() {
return mRequestInterceptors;
}
private ArrayList<RequestHeaderInterceptor> getRequestHeaderInterceptors() {
ArrayList<RequestHeaderInterceptor> requestHeaderInterceptors = new ArrayList<>();
for (RequestInterceptor requestInterceptor : mRequestInterceptors) {
if (requestInterceptor instanceof RequestHeaderInterceptor) {
requestHeaderInterceptors.add((RequestHeaderInterceptor) requestInterceptor);
}
}
return requestHeaderInterceptors;
}
public void deleteRequestHeaderInterceptor(String headerName) {
ListIterator<RequestInterceptor> requestInterceptorIterator = mRequestInterceptors.listIterator();
while (requestInterceptorIterator.hasNext()) {
RequestInterceptor currentRequestInterceptor = requestInterceptorIterator.next();
if (currentRequestInterceptor instanceof RequestHeaderInterceptor &&
((RequestHeaderInterceptor) currentRequestInterceptor).getHeaderName().equals(headerName)) {
requestInterceptorIterator.remove();
}
}
}
public ArrayList<ResponseInterceptor> getResponseInterceptors() {
return mResponseInterceptors;
}
public interface RequestInterceptor {
Request intercept(Request request) throws IOException;
}
public interface ResponseInterceptor {
Response intercept(Response response) throws IOException;
}
}

View File

@ -1,191 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods;
import com.owncloud.android.lib.common.http.HttpClient;
import okhttp3.Call;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Wrapper to perform http calls transparently by using:
* - OkHttp for non webdav methods
* - Dav4Android for webdav methods
*
* @author David González Verdugo
*/
public abstract class HttpBaseMethod {
protected OkHttpClient mOkHttpClient;
protected Request mRequest;
protected RequestBody mRequestBody;
protected Response mResponse;
protected String mResponseBodyString;
protected Call mCall;
protected HttpBaseMethod(URL url) {
mOkHttpClient = HttpClient.getOkHttpClient();
mRequest = new Request.Builder()
.url(HttpUrl.parse(url.toString()))
.build();
}
public int execute() throws Exception {
return onExecute();
}
public void abort() {
mCall.cancel();
}
public boolean isAborted() {
return mCall.isCanceled();
}
//////////////////////////////
// For override
//////////////////////////////
protected abstract int onExecute() throws Exception;
//////////////////////////////
// Getter
//////////////////////////////
// Request
public Headers getRequestHeaders() {
return mRequest.headers();
}
public String getRequestHeader(String name) {
return mRequest.header(name);
}
// Response
public int getStatusCode() {
return mResponse.code();
}
public String getStatusMessage() {
return mResponse.message();
}
public String getResponseBodyAsString() throws IOException {
if (mResponseBodyString == null && mResponse.body() != null) {
mResponseBodyString = mResponse.body().string();
}
return mResponseBodyString;
}
public InputStream getResponseBodyAsStream() {
if (mResponse.body() != null) {
return mResponse.body().byteStream();
}
return null;
}
public Headers getResponseHeaders() {
return mResponse.headers();
}
public String getResponseHeader(String headerName) {
return mResponse.header(headerName);
}
public boolean getRetryOnConnectionFailure() {
return mOkHttpClient.retryOnConnectionFailure();
}
//////////////////////////////
// Setter
//////////////////////////////
// Connection parameters
public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
mOkHttpClient = mOkHttpClient.newBuilder()
.retryOnConnectionFailure(retryOnConnectionFailure)
.build();
}
public void setReadTimeout(long readTimeout, TimeUnit timeUnit) {
mOkHttpClient = mOkHttpClient.newBuilder()
.readTimeout(readTimeout, timeUnit)
.build();
}
public void setConnectionTimeout(long connectionTimeout, TimeUnit timeUnit) {
mOkHttpClient = mOkHttpClient.newBuilder()
.readTimeout(connectionTimeout, timeUnit)
.build();
}
public void setFollowRedirects(boolean followRedirects) {
mOkHttpClient = mOkHttpClient.newBuilder()
.followRedirects(followRedirects)
.build();
}
// Request
public void addRequestHeader(String name, String value) {
mRequest = mRequest.newBuilder()
.addHeader(name, value)
.build();
}
/**
* Sets a header and replace it if already exists with that name
*
* @param name header name
* @param value header value
*/
public void setRequestHeader(String name, String value) {
mRequest = mRequest.newBuilder()
.header(name, value)
.build();
}
public void setRequestBody(RequestBody requestBody) {
mRequestBody = requestBody;
}
public void setUrl(HttpUrl url) {
mRequest = mRequest.newBuilder()
.url(url)
.build();
}
}

View File

@ -0,0 +1,187 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods
import com.owncloud.android.lib.common.http.HttpClient
import okhttp3.Call
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.InputStream
import java.net.MalformedURLException
import java.net.URL
import java.util.concurrent.TimeUnit
abstract class HttpBaseMethod constructor(url: URL) {
var httpUrl: HttpUrl = url.toHttpUrlOrNull() ?: throw MalformedURLException()
var request: Request
var followPermanentRedirects = false
abstract var response: Response
var call: Call? = null
var followRedirects: Boolean = true
var retryOnConnectionFailure: Boolean = true
var connectionTimeoutVal: Long? = null
var connectionTimeoutUnit: TimeUnit? = null
var readTimeoutVal: Long? = null
private set
var readTimeoutUnit: TimeUnit? = null
private set
init {
request = Request.Builder()
.url(httpUrl)
.build()
}
@Throws(Exception::class)
open fun execute(httpClient: HttpClient): Int {
val okHttpClient = httpClient.okHttpClient.newBuilder().apply {
retryOnConnectionFailure(retryOnConnectionFailure)
followRedirects(followRedirects)
readTimeoutUnit?.let { unit ->
readTimeoutVal?.let { readTimeout(it, unit) }
}
connectionTimeoutUnit?.let { unit ->
connectionTimeoutVal?.let { connectTimeout(it, unit) }
}
}.build()
return onExecute(okHttpClient)
}
open fun setUrl(url: HttpUrl) {
request = request.newBuilder()
.url(url)
.build()
}
/****************
*** Requests ***
****************/
fun getRequestHeader(name: String): String? {
return request.header(name)
}
fun getRequestHeadersAsHashMap(): HashMap<String, String?> {
val headers: HashMap<String, String?> = HashMap()
val superHeaders: Set<String> = request.headers.names()
superHeaders.forEach {
headers[it] = getRequestHeader(it)
}
return headers
}
open fun addRequestHeader(name: String, value: String) {
request = request.newBuilder()
.addHeader(name, value)
.build()
}
/**
* Sets a header and replace it if already exists with that name
*
* @param name header name
* @param value header value
*/
open fun setRequestHeader(name: String, value: String) {
request = request.newBuilder()
.header(name, value)
.build()
}
/****************
*** Response ***
****************/
val statusCode: Int
get() = response.code
val statusMessage: String
get() = response.message
// Headers
open fun getResponseHeaders(): Headers? {
return response.headers
}
open fun getResponseHeader(headerName: String): String? {
return response.header(headerName)
}
// Body
fun getResponseBodyAsString(): String? = response.body?.string()
open fun getResponseBodyAsStream(): InputStream? {
return response.body?.byteStream()
}
/**
* returns the final url after following the last redirect.
*/
open fun getFinalUrl() = response.request.url
/*************************
*** Connection Params ***
*************************/
//////////////////////////////
// Setter
//////////////////////////////
// Connection parameters
open fun setReadTimeout(readTimeout: Long, timeUnit: TimeUnit) {
readTimeoutVal = readTimeout
readTimeoutUnit = timeUnit
}
open fun setConnectionTimeout(
connectionTimeout: Long,
timeUnit: TimeUnit
) {
connectionTimeoutVal = connectionTimeout
connectionTimeoutUnit = timeUnit
}
/************
*** Call ***
************/
open fun abort() {
call?.cancel()
}
open val isAborted: Boolean
get() = call?.isCanceled() ?: false
//////////////////////////////
// For override
//////////////////////////////
@Throws(Exception::class)
protected abstract fun onExecute(okHttpClient: OkHttpClient): Int
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,29 +21,23 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav
package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.OkHttpClient
import java.io.IOException
import java.net.URL
/**
* OkHttp delete calls wrapper
*
* @author David González Verdugo
*/
public class DeleteMethod extends HttpMethod {
public DeleteMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
class DeleteMethod(url: URL) : HttpMethod(url) {
@Throws(IOException::class)
override fun onExecute(okHttpClient: OkHttpClient): Int {
request = request.newBuilder()
.delete()
.build();
return super.onExecute();
.build()
return super.onExecute(okHttpClient)
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,29 +21,23 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav
package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.OkHttpClient
import java.io.IOException
import java.net.URL
/**
* OkHttp get calls wrapper
*
* @author David González Verdugo
*/
public class GetMethod extends HttpMethod {
public GetMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
class GetMethod(url: URL) : HttpMethod(url) {
@Throws(IOException::class)
override fun onExecute(okHttpClient: OkHttpClient): Int {
request = request.newBuilder()
.get()
.build();
return super.onExecute();
.build()
return super.onExecute(okHttpClient)
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,29 +21,27 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav
package com.owncloud.android.lib.common.http.methods.nonwebdav;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import java.io.IOException;
import java.net.URL;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod
import okhttp3.OkHttpClient
import okhttp3.Response
import java.net.URL
/**
* Wrapper to perform OkHttp calls
*
* @author David González Verdugo
*/
public abstract class HttpMethod extends HttpBaseMethod {
abstract class HttpMethod(
url: URL
) : HttpBaseMethod(url) {
public HttpMethod(URL url) {
super(url);
}
override lateinit var response: Response
@Override
public int onExecute() throws IOException {
mCall = mOkHttpClient.newCall(mRequest);
mResponse = mCall.execute();
return super.getStatusCode();
public override fun onExecute(okHttpClient: OkHttpClient): Int {
call = okHttpClient.newCall(request)
call?.let { response = it.execute() }
return super.statusCode
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,29 +21,27 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav
package com.owncloud.android.lib.common.http.methods.nonwebdav;
import java.io.IOException;
import java.net.URL;
import okhttp3.OkHttpClient
import okhttp3.RequestBody
import java.io.IOException
import java.net.URL
/**
* OkHttp post calls wrapper
*
* @author David González Verdugo
*/
public class PostMethod extends HttpMethod {
public PostMethod(URL url) {
super(url);
}
@Override
public int onExecute() throws IOException {
mRequest = mRequest.newBuilder()
.post(mRequestBody)
.build();
return super.onExecute();
class PostMethod(
url: URL,
private val postRequestBody: RequestBody
) : HttpMethod(url) {
@Throws(IOException::class)
override fun onExecute(okHttpClient: OkHttpClient): Int {
request = request.newBuilder()
.post(postRequestBody)
.build()
return super.onExecute(okHttpClient)
}
}

View File

@ -0,0 +1,47 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.nonwebdav
import okhttp3.OkHttpClient
import okhttp3.RequestBody
import java.io.IOException
import java.net.URL
/**
* OkHttp put calls wrapper
*
* @author David González Verdugo
*/
class PutMethod(
url: URL,
private val putRequestBody: RequestBody
) : HttpMethod(url) {
@Throws(IOException::class)
override fun onExecute(okHttpClient: OkHttpClient): Int {
request = request.newBuilder()
.put(putRequestBody)
.build()
return super.onExecute(okHttpClient)
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,12 +21,11 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav
package com.owncloud.android.lib.common.http.methods.webdav;
import kotlin.Unit;
import java.net.URL;
import at.bitfire.dav4jvm.DavOCResource
import okhttp3.Response
import java.net.URL
/**
* Copy calls wrapper
@ -34,24 +33,20 @@ import java.net.URL;
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class CopyMethod extends DavMethod {
final String destinationUrl;
final boolean forceOverride;
public CopyMethod(URL url, String destinationUrl, boolean forceOverride) {
super(url);
this.destinationUrl = destinationUrl;
this.forceOverride = forceOverride;
class CopyMethod(
val url: URL,
private val destinationUrl: String,
val forceOverride: Boolean = false
) : DavMethod(url) {
@Throws(Exception::class)
public override fun onDavExecute(davResource: DavOCResource): Int {
davResource.copy(
destinationUrl,
forceOverride,
super.getRequestHeadersAsHashMap()
) { callBackResponse: Response ->
response = callBackResponse
}
@Override
public int onExecute() throws Exception {
mDavResource.copy(destinationUrl, forceOverride, response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
return super.statusCode
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,13 +21,12 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
package com.owncloud.android.lib.common.http.methods.webdav
/**
* @author David González Verdugo
*/
public class DavConstants {
public static final int DEPTH_0 = 0;
public static final int DEPTH_1 = 1;
object DavConstants {
const val DEPTH_0 = 0
const val DEPTH_1 = 1
}

View File

@ -1,158 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import at.bitfire.dav4android.Constants;
import at.bitfire.dav4android.DavOCResource;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.dav4android.exception.RedirectException;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import okhttp3.HttpUrl;
import okhttp3.Protocol;
import okhttp3.Response;
import okhttp3.ResponseBody;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Wrapper to perform WebDAV (dav4android) calls
*
* @author David González Verdugo
*/
public abstract class DavMethod extends HttpBaseMethod {
protected DavOCResource mDavResource;
protected DavMethod(URL url) {
super(url);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(url.toString()),
Constants.INSTANCE.getLog());
}
@Override
public void abort() {
mDavResource.cancelCall();
}
@Override
public int execute() throws Exception {
try {
return onExecute();
} catch (HttpException httpException) {
// Modify responses with information gathered from exceptions
if (httpException instanceof RedirectException) {
mResponse = new Response.Builder()
.header(
HttpConstants.LOCATION_HEADER, ((RedirectException) httpException).getRedirectLocation()
)
.code(httpException.getCode())
.request(mRequest)
.message(httpException.getMessage())
.protocol(Protocol.HTTP_1_1)
.build();
} else if (mResponse != null) {
ResponseBody responseBody = ResponseBody.create(
mResponse.body().contentType(),
httpException.getResponseBody()
);
mResponse = mResponse.newBuilder()
.body(responseBody)
.build();
}
return httpException.getCode();
}
}
//////////////////////////////
// Setter
//////////////////////////////
// Connection parameters
@Override
public void setReadTimeout(long readTimeout, TimeUnit timeUnit) {
super.setReadTimeout(readTimeout, timeUnit);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public void setConnectionTimeout(long connectionTimeout, TimeUnit timeUnit) {
super.setConnectionTimeout(connectionTimeout, timeUnit);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public void setFollowRedirects(boolean followRedirects) {
super.setFollowRedirects(followRedirects);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public void setUrl(HttpUrl url) {
super.setUrl(url);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public boolean getRetryOnConnectionFailure() {
return false; //TODO: implement me
}
//////////////////////////////
// Getter
//////////////////////////////
@Override
public void setRetryOnConnectionFailure(boolean retryOnConnectionFailure) {
super.setRetryOnConnectionFailure(retryOnConnectionFailure);
mDavResource = new DavOCResource(
mOkHttpClient,
HttpUrl.parse(mRequest.url().toString()),
Constants.INSTANCE.getLog());
}
@Override
public boolean isAborted() {
return mDavResource.isCallAborted();
}
}

View File

@ -0,0 +1,97 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav
import at.bitfire.dav4jvm.Dav4jvm.log
import at.bitfire.dav4jvm.DavOCResource
import at.bitfire.dav4jvm.exception.HttpException
import at.bitfire.dav4jvm.exception.RedirectException
import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod
import okhttp3.OkHttpClient
import okhttp3.Protocol
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import java.net.URL
/**
* Wrapper to perform WebDAV (dav4android) calls
*
* @author David González Verdugo
*/
abstract class DavMethod protected constructor(url: URL) : HttpBaseMethod(url) {
override lateinit var response: Response
private var davResource: DavOCResource? = null
override fun abort() {
davResource?.cancelCall()
}
protected abstract fun onDavExecute(davResource: DavOCResource): Int
@Throws(Exception::class)
override fun onExecute(okHttpClient: OkHttpClient): Int {
return try {
davResource = DavOCResource(
okHttpClient.newBuilder().followRedirects(false).build(),
httpUrl,
log
)
onDavExecute(davResource!!)
} catch (httpException: HttpException) {
// Modify responses with information gathered from exceptions
if (httpException is RedirectException) {
response = Response.Builder()
.header(
HttpConstants.LOCATION_HEADER, httpException.redirectLocation
)
.code(httpException.code)
.request(request)
.message(httpException.message ?: "")
.protocol(Protocol.HTTP_1_1)
.build()
} else {
// The check below should be included in okhttp library, method ResponseBody.create(
// TODO check most recent versions of okhttp to see if this is already fixed and try to update if so
if (response.body?.contentType() != null) {
val responseBody = (httpException.responseBody ?: "").toResponseBody(response.body?.contentType())
response = response.newBuilder()
.body(responseBody)
.build()
}
}
httpException.code
}
}
//////////////////////////////
// Getter
//////////////////////////////
override val isAborted: Boolean
get() = davResource?.isCallAborted() ?: false
}

View File

@ -1,15 +0,0 @@
package com.owncloud.android.lib.common.http.methods.webdav;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.PropertyUtils;
public class DavUtils {
public static final Property.Name[] getAllPropset() {
return PropertyUtils.INSTANCE.getAllPropSet();
}
public static final Property.Name[] getQuotaPropSet() {
return PropertyUtils.INSTANCE.getQuotaPropset();
}
}

View File

@ -0,0 +1,60 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav
import at.bitfire.dav4jvm.Property
import at.bitfire.dav4jvm.PropertyUtils.getQuotaPropset
import at.bitfire.dav4jvm.property.CreationDate
import at.bitfire.dav4jvm.property.DisplayName
import at.bitfire.dav4jvm.property.GetContentLength
import at.bitfire.dav4jvm.property.GetContentType
import at.bitfire.dav4jvm.property.GetETag
import at.bitfire.dav4jvm.property.GetLastModified
import at.bitfire.dav4jvm.property.OCId
import at.bitfire.dav4jvm.property.OCPermissions
import at.bitfire.dav4jvm.property.OCPrivatelink
import at.bitfire.dav4jvm.property.OCSize
import at.bitfire.dav4jvm.property.ResourceType
import com.owncloud.android.lib.common.http.methods.webdav.properties.OCShareTypes
object DavUtils {
@JvmStatic val allPropSet: Array<Property.Name>
get() = arrayOf(
DisplayName.NAME,
GetContentType.NAME,
ResourceType.NAME,
GetContentLength.NAME,
GetLastModified.NAME,
CreationDate.NAME,
GetETag.NAME,
OCPermissions.NAME,
OCId.NAME,
OCSize.NAME,
OCPrivatelink.NAME,
OCShareTypes.NAME,
)
val quotaPropSet: Array<Property.Name>
get() = getQuotaPropset()
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,12 +21,11 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav
package com.owncloud.android.lib.common.http.methods.webdav;
import kotlin.Unit;
import java.net.URL;
import at.bitfire.dav4jvm.DavOCResource
import okhttp3.Response
import java.net.URL
/**
* MkCol calls wrapper
@ -34,18 +33,15 @@ import java.net.URL;
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class MkColMethod extends DavMethod {
public MkColMethod(URL url) {
super(url);
class MkColMethod(url: URL) : DavMethod(url) {
@Throws(Exception::class)
public override fun onDavExecute(davResource: DavOCResource): Int {
davResource.mkCol(
xmlBody = null,
listOfHeaders = super.getRequestHeadersAsHashMap()
) { callBackResponse: Response ->
response = callBackResponse
}
@Override
public int onExecute() throws Exception {
mDavResource.mkCol(null, response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
return super.statusCode
}
}

View File

@ -1,61 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import com.owncloud.android.lib.common.http.HttpConstants;
import kotlin.Unit;
import java.net.URL;
/**
* Move calls wrapper
*
* @author Christian Schabesberger
* @author David González Verdugo
*/
public class MoveMethod extends DavMethod {
final String destinationUrl;
final boolean forceOverride;
public MoveMethod(URL url, String destinationUrl, boolean forceOverride) {
super(url);
this.destinationUrl = destinationUrl;
this.forceOverride = forceOverride;
}
@Override
public int onExecute() throws Exception {
mDavResource.move(
destinationUrl,
forceOverride,
super.getRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER),
super.getRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER), response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
}
}

View File

@ -0,0 +1,53 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav
import at.bitfire.dav4jvm.DavOCResource
import okhttp3.Response
import java.net.URL
/**
* Move calls wrapper
*
* @author Christian Schabesberger
* @author David González Verdugo
*/
class MoveMethod(
url: URL,
private val destinationUrl: String,
val forceOverride: Boolean = false
) : DavMethod(url) {
@Throws(Exception::class)
override fun onDavExecute(davResource: DavOCResource): Int {
davResource.move(
destinationUrl,
forceOverride,
super.getRequestHeadersAsHashMap()
) { callBackResponse: Response ->
response = callBackResponse
}
return super.statusCode
}
}

View File

@ -1,94 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import at.bitfire.dav4android.Property;
import at.bitfire.dav4android.Response;
import at.bitfire.dav4android.exception.DavException;
import kotlin.Unit;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* Propfind calls wrapper
*
* @author David González Verdugo
*/
public class PropfindMethod extends DavMethod {
// request
private final int mDepth;
private final Property.Name[] mPropertiesToRequest;
// response
private final List<Response> mMembers;
private Response mRoot;
public PropfindMethod(URL url, int depth, Property.Name[] propertiesToRequest) {
super(url);
mDepth = depth;
mPropertiesToRequest = propertiesToRequest;
mMembers = new ArrayList<>();
mRoot = null;
}
@Override
public int onExecute() throws IOException, DavException {
mDavResource.propfind(mDepth, mPropertiesToRequest,
(Response response, Response.HrefRelation hrefRelation) -> {
switch (hrefRelation) {
case MEMBER:
mMembers.add(response);
break;
case SELF:
mRoot = response;
break;
case OTHER:
default:
}
return Unit.INSTANCE;
}, response -> {
mResponse = response;
return Unit.INSTANCE;
});
return getStatusCode();
}
public int getDepth() {
return mDepth;
}
public List<Response> getMembers() {
return mMembers;
}
public Response getRoot() {
return mRoot;
}
}

View File

@ -0,0 +1,73 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav
import at.bitfire.dav4jvm.DavOCResource
import at.bitfire.dav4jvm.Property
import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.Response.HrefRelation
import at.bitfire.dav4jvm.exception.DavException
import java.io.IOException
import java.net.URL
/**
* Propfind calls wrapper
*
* @author David González Verdugo
*/
class PropfindMethod(
url: URL,
private val depth: Int,
private val propertiesToRequest: Array<Property.Name>
) : DavMethod(url) {
// response
val members: MutableList<Response>
var root: Response?
private set
@Throws(IOException::class, DavException::class)
public override fun onDavExecute(davResource: DavOCResource): Int {
davResource.propfind(
depth = depth,
reqProp = propertiesToRequest,
listOfHeaders = super.getRequestHeadersAsHashMap(),
callback = { response: Response, hrefRelation: HrefRelation ->
when (hrefRelation) {
HrefRelation.MEMBER -> members.add(response)
HrefRelation.SELF -> this.root = response
HrefRelation.OTHER -> {
}
}
}, rawCallback = { callBackResponse: okhttp3.Response ->
response = callBackResponse
})
return statusCode
}
init {
members = arrayListOf()
this.root = null
}
}

View File

@ -1,61 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav;
import at.bitfire.dav4android.exception.HttpException;
import com.owncloud.android.lib.common.http.HttpConstants;
import kotlin.Unit;
import java.io.IOException;
import java.net.URL;
/**
* Put calls wrapper
*
* @author David González Verdugo
*/
public class PutMethod extends DavMethod {
public PutMethod(URL url) {
super(url);
}
;
@Override
public int onExecute() throws IOException, HttpException {
mDavResource.put(
mRequestBody,
super.getRequestHeader(HttpConstants.IF_MATCH_HEADER),
super.getRequestHeader(HttpConstants.CONTENT_TYPE_HEADER),
super.getRequestHeader(HttpConstants.OC_TOTAL_LENGTH_HEADER),
super.getRequestHeader(HttpConstants.OC_X_OC_MTIME_HEADER), response -> {
mResponse = response;
return Unit.INSTANCE;
});
return super.getStatusCode();
}
}

View File

@ -0,0 +1,53 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav
import at.bitfire.dav4jvm.DavOCResource
import at.bitfire.dav4jvm.exception.HttpException
import com.owncloud.android.lib.common.http.HttpConstants
import okhttp3.RequestBody
import java.io.IOException
import java.net.URL
/**
* Put calls wrapper
*
* @author David González Verdugo
*/
class PutMethod(
url: URL,
private val putRequestBody: RequestBody
) : DavMethod(url) {
@Throws(IOException::class, HttpException::class)
public override fun onDavExecute(davResource: DavOCResource): Int {
davResource.put(
putRequestBody,
super.getRequestHeader(HttpConstants.IF_MATCH_HEADER),
getRequestHeadersAsHashMap()
) { callBackResponse ->
response = callBackResponse
}
return super.statusCode
}
}

View File

@ -1,7 +1,5 @@
/* ownCloud Android Library is available under MIT license
*
* @author David A. Velasco
* Copyright (C) 2017 ownCloud GmbH.
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,24 +21,24 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.http.methods.webdav.properties
package com.owncloud.android.lib.common.authentication.oauth;
import at.bitfire.dav4jvm.Property
import at.bitfire.dav4jvm.XmlUtils
import org.xmlpull.v1.XmlPullParser
public enum OAuth2GrantType {
AUTHORIZATION_CODE("authorization_code"),
IMPLICIT("implicit"),
PASSWORD("password"),
CLIENT_CREDENTIAL("client_credentials"),
REFRESH_TOKEN("refresh_token") // not a grant type conceptually, but used as such to refresh access tokens
;
class OCShareTypes : ShareTypeListProperty() {
private String mValue;
class Factory : ShareTypeListProperty.Factory() {
OAuth2GrantType(String value) {
mValue = value;
override fun create(parser: XmlPullParser) =
create(parser, OCShareTypes())
override fun getName(): Property.Name = NAME
}
public String getValue() {
return mValue;
companion object {
@JvmField
val NAME = Property.Name(XmlUtils.NS_OWNCLOUD, "share-types")
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -21,26 +21,26 @@
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.sampleclient;
package com.owncloud.android.lib.common.http.methods.webdav.properties
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import at.bitfire.dav4jvm.Property
import at.bitfire.dav4jvm.PropertyFactory
import at.bitfire.dav4jvm.XmlUtils
import org.xmlpull.v1.XmlPullParser
import java.util.LinkedList
import com.owncloud.android.lib.resources.files.RemoteFile;
abstract class ShareTypeListProperty : Property {
public class FilesArrayAdapter extends ArrayAdapter<RemoteFile> {
val shareTypes = LinkedList<String>()
public FilesArrayAdapter(Context context, int resource) {
super(context, resource);
override fun toString() = "share types =[" + shareTypes.joinToString(", ") + "]"
abstract class Factory : PropertyFactory {
fun create(parser: XmlPullParser, list: ShareTypeListProperty): ShareTypeListProperty {
XmlUtils.readTextPropertyList(parser, Property.Name(XmlUtils.NS_OWNCLOUD, "share-type"), list.shareTypes)
return list
}
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView = (TextView) super.getView(position, convertView, parent);
textView.setText(getItem(position).getRemotePath());
return textView;
}
}

View File

@ -24,7 +24,7 @@
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import timber.log.Timber;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
@ -33,7 +33,6 @@ import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
@ -44,22 +43,17 @@ import java.security.cert.X509Certificate;
*/
public class AdvancedX509TrustManager implements X509TrustManager {
private static final String TAG = AdvancedX509TrustManager.class.getSimpleName();
private X509TrustManager mStandardTrustManager = null;
private X509TrustManager mStandardTrustManager;
private KeyStore mKnownServersKeyStore;
/**
* Constructor for AdvancedX509TrustManager
*
* @param knownServersKeyStore Local certificates store with server certificates explicitly trusted by the user.
* @throws CertStoreException When no default X509TrustManager instance was found in the system.
*/
public AdvancedX509TrustManager(KeyStore knownServersKeyStore)
throws NoSuchAlgorithmException, KeyStoreException, CertStoreException {
public AdvancedX509TrustManager(KeyStore knownServersKeyStore) throws NoSuchAlgorithmException, KeyStoreException {
super();
TrustManagerFactory factory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
factory.init((KeyStore) null);
mStandardTrustManager = findX509TrustManager(factory);
@ -71,13 +65,12 @@ public class AdvancedX509TrustManager implements X509TrustManager {
*
* @param factory TrustManagerFactory to inspect in the search for a X509TrustManager
* @return The first X509TrustManager found in factory.
* @throws CertStoreException When no X509TrustManager instance was found in factory
*/
private X509TrustManager findX509TrustManager(TrustManagerFactory factory) throws CertStoreException {
TrustManager tms[] = factory.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
return (X509TrustManager) tms[i];
private X509TrustManager findX509TrustManager(TrustManagerFactory factory) {
TrustManager[] tms = factory.getTrustManagers();
for (TrustManager tm : tms) {
if (tm instanceof X509TrustManager) {
return (X509TrustManager) tm;
}
}
return null;
@ -116,7 +109,7 @@ public class AdvancedX509TrustManager implements X509TrustManager {
previousCause = cause;
cause = cause.getCause();
}
if (cause != null && cause instanceof CertPathValidatorException) {
if (cause instanceof CertPathValidatorException) {
result.setCertPathValidatorException((CertPathValidatorException) cause);
} else {
result.setOtherCertificateException(c);
@ -141,7 +134,7 @@ public class AdvancedX509TrustManager implements X509TrustManager {
try {
return (mKnownServersKeyStore.getCertificateAlias(cert) != null);
} catch (KeyStoreException e) {
Log_OC.d(TAG, "Fail while checking certificate in the known-servers store");
Timber.e(e, "Fail while checking certificate in the known-servers store");
return false;
}
}

View File

@ -1,135 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import android.util.Log;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.MediaType;
import okio.BufferedSink;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Iterator;
/**
* A Request body that represents a file chunk and include information about the progress when uploading it
*
* @author David González Verdugo
*/
public class ChunkFromFileRequestBody extends FileRequestBody {
private static final String TAG = ChunkFromFileRequestBody.class.getSimpleName();
//private final File mFile;
private final FileChannel mChannel;
private final long mChunkSize;
private long mOffset;
private long mTransferred;
private ByteBuffer mBuffer = ByteBuffer.allocate(4096);
public ChunkFromFileRequestBody(File file, MediaType contentType, FileChannel channel, long chunkSize) {
super(file, contentType);
if (channel == null) {
throw new IllegalArgumentException("File may not be null");
}
if (chunkSize <= 0) {
throw new IllegalArgumentException("Chunk size must be greater than zero");
}
this.mChannel = channel;
this.mChunkSize = chunkSize;
mOffset = 0;
mTransferred = 0;
}
@Override
public long contentLength() {
try {
return Math.min(mChunkSize, mChannel.size() - mChannel.position());
} catch (IOException e) {
return mChunkSize;
}
}
@Override
public void writeTo(BufferedSink sink) {
int readCount;
Iterator<OnDatatransferProgressListener> it;
try {
mChannel.position(mOffset);
long size = mFile.length();
if (size == 0) {
size = -1;
}
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
while (mChannel.position() < maxCount) {
Log_OC.d(TAG, "Sink buffer size: " + sink.buffer().size());
readCount = mChannel.read(mBuffer);
Log_OC.d(TAG, "Read " + readCount + " bytes from file channel to " + mBuffer.toString());
sink.buffer().write(mBuffer.array(), 0, readCount);
sink.flush();
Log_OC.d(TAG, "Write " + readCount + " bytes to sink buffer with size " + sink.buffer().size());
mBuffer.clear();
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
mTransferred += readCount;
}
synchronized (mDataTransferListeners) {
it = mDataTransferListeners.iterator();
while (it.hasNext()) {
it.next().onTransferProgress(readCount, mTransferred, size, mFile.getAbsolutePath());
}
}
}
Log.d(TAG, "Chunk with size " + mChunkSize + " written in request body");
} catch (Exception exception) {
Log.e(TAG, exception.toString());
// // any read problem will be handled as if the file is not there
// if (io instanceof FileNotFoundException) {
// throw io;
// } else {
// FileNotFoundException fnf = new FileNotFoundException("Exception reading source file");
// fnf.initCause(io);
// throw fnf;
// }
}
}
public void setOffset(long offset) {
this.mOffset = offset;
}
}

View File

@ -0,0 +1,92 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network
import com.owncloud.android.lib.resources.files.chunks.ChunkedUploadFromFileSystemOperation.Companion.CHUNK_SIZE
import okhttp3.MediaType
import okio.BufferedSink
import timber.log.Timber
import java.io.File
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
/**
* A Request body that represents a file chunk and include information about the progress when uploading it
*
* @author David González Verdugo
*/
class ChunkFromFileRequestBody(
file: File,
contentType: MediaType?,
private val channel: FileChannel,
private val chunkSize: Long = CHUNK_SIZE
) : FileRequestBody(file, contentType) {
private var offset: Long = 0
private var alreadyTransferred: Long = 0
private val buffer = ByteBuffer.allocate(4_096)
init {
require(chunkSize > 0) { "Chunk size must be greater than zero" }
}
override fun contentLength(): Long {
return chunkSize.coerceAtMost(channel.size() - channel.position())
}
override fun writeTo(sink: BufferedSink) {
var readCount: Int
var iterator: Iterator<OnDatatransferProgressListener>
try {
channel.position(offset)
val maxCount = (offset + chunkSize).coerceAtMost(channel.size())
while (channel.position() < maxCount) {
readCount = channel.read(buffer)
val bytesToWriteInBuffer = readCount.toLong().coerceAtMost(file.length() - alreadyTransferred).toInt()
sink.buffer.write(buffer.array(), 0, bytesToWriteInBuffer)
sink.flush()
buffer.clear()
if (alreadyTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
alreadyTransferred += readCount.toLong()
}
synchronized(dataTransferListeners) {
iterator = dataTransferListeners.iterator()
while (iterator.hasNext()) {
iterator.next().onTransferProgress(readCount.toLong(), alreadyTransferred, file.length(), file.absolutePath)
}
}
}
} catch (exception: Exception) {
Timber.e(exception, "Transferred " + alreadyTransferred + " bytes from a total of " + file.length())
}
}
fun setOffset(newOffset: Long) {
offset = newOffset
}
}

View File

@ -0,0 +1,117 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network
import android.content.ContentResolver
import android.net.Uri
import android.provider.OpenableColumns
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okio.BufferedSink
import okio.Source
import okio.source
import timber.log.Timber
import java.io.IOException
class ContentUriRequestBody(
private val contentResolver: ContentResolver,
private val contentUri: Uri
) : RequestBody(), ProgressiveDataTransferer {
private val dataTransferListeners: MutableSet<OnDatatransferProgressListener> = HashSet()
val fileSize: Long = contentResolver.query(contentUri, null, null, null, null)?.use { cursor ->
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
cursor.moveToFirst()
cursor.getLong(sizeIndex)
} ?: -1
override fun contentType(): MediaType? {
val contentType = contentResolver.getType(contentUri) ?: return null
return contentType.toMediaTypeOrNull()
}
override fun contentLength(): Long {
return fileSize
}
override fun writeTo(sink: BufferedSink) {
val inputStream = contentResolver.openInputStream(contentUri)
?: throw IOException("Couldn't open content URI for reading: $contentUri")
val previousTime = System.currentTimeMillis()
sink.writeAndUpdateProgress(inputStream.source())
inputStream.source().close()
val laterTime = System.currentTimeMillis()
Timber.d("Difference - ${laterTime - previousTime} milliseconds")
}
private fun BufferedSink.writeAndUpdateProgress(source: Source) {
var iterator: Iterator<OnDatatransferProgressListener>
try {
var totalBytesRead = 0L
var read: Long
while (source.read(this.buffer, BYTES_TO_READ).also { read = it } != -1L) {
totalBytesRead += read
this.flush()
synchronized(dataTransferListeners) {
iterator = dataTransferListeners.iterator()
while (iterator.hasNext()) {
iterator.next().onTransferProgress(read, totalBytesRead, fileSize, contentUri.toString())
}
}
}
} catch (e: Exception) {
Timber.e(e)
}
}
override fun addDatatransferProgressListener(listener: OnDatatransferProgressListener) {
synchronized(dataTransferListeners) {
dataTransferListeners.add(listener)
}
}
override fun addDatatransferProgressListeners(listeners: MutableCollection<OnDatatransferProgressListener>) {
synchronized(dataTransferListeners) {
dataTransferListeners.addAll(listeners)
}
}
override fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener) {
synchronized(dataTransferListeners) {
dataTransferListeners.remove(listener)
}
}
companion object {
private const val BYTES_TO_READ = 4_096L
}
}

View File

@ -1,118 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import android.util.Log;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* A Request body that represents a file and include information about the progress when uploading it
*
* @author David González Verdugo
*/
public class FileRequestBody extends RequestBody implements ProgressiveDataTransferer {
private static final String TAG = FileRequestBody.class.getSimpleName();
protected File mFile;
private MediaType mContentType;
Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
public FileRequestBody(File file, MediaType contentType) {
mFile = file;
mContentType = contentType;
}
@Override
public MediaType contentType() {
return mContentType;
}
@Override
public long contentLength() {
return mFile.length();
}
@Override
public void writeTo(BufferedSink sink) {
Source source;
Iterator<OnDatatransferProgressListener> it;
try {
source = Okio.source(mFile);
long transferred = 0;
long read;
while ((read = source.read(sink.buffer(), 4096)) != -1) {
transferred += read;
sink.flush();
synchronized (mDataTransferListeners) {
it = mDataTransferListeners.iterator();
while (it.hasNext()) {
it.next().onTransferProgress(read, transferred, mFile.length(), mFile.getAbsolutePath());
}
}
}
Log.d(TAG, "File with name " + mFile.getName() + " and size " + mFile.length() +
" written in request body");
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void addDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.add(listener);
}
}
@Override
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.addAll(listeners);
}
}
@Override
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener) {
synchronized (mDataTransferListeners) {
mDataTransferListeners.remove(listener);
}
}
}

View File

@ -0,0 +1,97 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network
import okhttp3.MediaType
import okhttp3.RequestBody
import okio.BufferedSink
import okio.Source
import okio.source
import timber.log.Timber
import java.io.File
import java.util.HashSet
/**
* A Request body that represents a file and include information about the progress when uploading it
*
* @author David González Verdugo
*/
open class FileRequestBody(
val file: File,
private val contentType: MediaType?,
) : RequestBody(), ProgressiveDataTransferer {
val dataTransferListeners: MutableSet<OnDatatransferProgressListener> = HashSet()
override fun isOneShot(): Boolean = true
override fun contentType(): MediaType? = contentType
override fun contentLength(): Long = file.length()
override fun writeTo(sink: BufferedSink) {
val source: Source
var it: Iterator<OnDatatransferProgressListener>
try {
source = file.source()
var transferred: Long = 0
var read: Long
while (source.read(sink.buffer, BYTES_TO_READ).also { read = it } != -1L) {
transferred += read
sink.flush()
synchronized(dataTransferListeners) {
it = dataTransferListeners.iterator()
while (it.hasNext()) {
it.next().onTransferProgress(read, transferred, file.length(), file.absolutePath)
}
}
}
Timber.d("File with name ${file.name} and size ${file.length()} written in request body")
} catch (e: Exception) {
Timber.e(e)
}
}
override fun addDatatransferProgressListener(listener: OnDatatransferProgressListener) {
synchronized(dataTransferListeners) {
dataTransferListeners.add(listener)
}
}
override fun addDatatransferProgressListeners(listeners: Collection<OnDatatransferProgressListener>) {
synchronized(dataTransferListeners) {
dataTransferListeners.addAll(listeners)
}
}
override fun removeDatatransferProgressListener(listener: OnDatatransferProgressListener) {
synchronized(dataTransferListeners) {
dataTransferListeners.remove(listener)
}
}
companion object {
private const val BYTES_TO_READ = 4_096L
}
}

View File

@ -26,8 +26,7 @@ package com.owncloud.android.lib.common.network;
import android.content.Context;
import com.owncloud.android.lib.common.utils.Log_OC;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import timber.log.Timber;
import java.io.File;
import java.io.FileInputStream;
@ -42,25 +41,6 @@ import java.security.cert.CertificateException;
public class NetworkUtils {
/**
* Default timeout for waiting data from the server
*/
public static final int DEFAULT_DATA_TIMEOUT = 60000;
/**
* Default timeout for establishing a connection
*/
public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
/**
* Standard name for protocol TLS version 1.2 in Java Secure Socket Extension (JSSE) API
*/
public static final String PROTOCOL_TLSv1_2 = "TLSv1.2";
/**
* Standard name for protocol TLS version 1.0 in JSSE API
*/
public static final String PROTOCOL_TLSv1_0 = "TLSv1";
final private static String TAG = NetworkUtils.class.getSimpleName();
private static X509HostnameVerifier mHostnameVerifier = null;
private static String LOCAL_TRUSTSTORE_FILENAME = "knownServers.bks";
private static String LOCAL_TRUSTSTORE_PASSWORD = "password";
@ -88,7 +68,7 @@ public class NetworkUtils {
//mKnownServersStore = KeyStore.getInstance("BKS");
mKnownServersStore = KeyStore.getInstance(KeyStore.getDefaultType());
File localTrustStoreFile = new File(context.getFilesDir(), LOCAL_TRUSTSTORE_FILENAME);
Log_OC.d(TAG, "Searching known-servers store at " + localTrustStoreFile.getAbsolutePath());
Timber.d("Searching known-servers store at %s", localTrustStoreFile.getAbsolutePath());
if (localTrustStoreFile.exists()) {
InputStream in = new FileInputStream(localTrustStoreFile);
try {
@ -109,22 +89,9 @@ public class NetworkUtils {
KeyStore knownServers = getKnownServersStore(context);
knownServers.setCertificateEntry(Integer.toString(cert.hashCode()), cert);
FileOutputStream fos = null;
try {
fos = context.openFileOutput(LOCAL_TRUSTSTORE_FILENAME, Context.MODE_PRIVATE);
try (FileOutputStream fos = context.openFileOutput(LOCAL_TRUSTSTORE_FILENAME, Context.MODE_PRIVATE)) {
knownServers.store(fos, LOCAL_TRUSTSTORE_PASSWORD.toCharArray());
} finally {
fos.close();
}
}
public static boolean isCertInKnownServersStore(Certificate cert, Context context)
throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
KeyStore knownServers = getKnownServersStore(context);
Log_OC.d(TAG, "Certificate - HashCode: " + cert.hashCode() + " "
+ Boolean.toString(knownServers.isCertificateEntry(Integer.toString(cert.hashCode()))));
return knownServers.isCertificateEntry(Integer.toString(cert.hashCode()));
}
}

View File

@ -28,10 +28,10 @@ import java.util.Collection;
public interface ProgressiveDataTransferer {
public void addDatatransferProgressListener(OnDatatransferProgressListener listener);
void addDatatransferProgressListener(OnDatatransferProgressListener listener);
public void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners);
void addDatatransferProgressListeners(Collection<OnDatatransferProgressListener> listeners);
public void removeDatatransferProgressListener(OnDatatransferProgressListener listener);
void removeDatatransferProgressListener(OnDatatransferProgressListener listener);
}

View File

@ -1,145 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2016 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import javax.net.ssl.SSLSocket;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicReference;
/**
* Enables the support of Server Name Indication if existing
* in the underlying network implementation.
* <p>
* Build as a singleton.
*
* @author David A. Velasco
*/
public class ServerNameIndicator {
private static final String TAG = ServerNameIndicator.class.getSimpleName();
private static final AtomicReference<ServerNameIndicator> mSingleInstance = new AtomicReference<ServerNameIndicator>();
private static final String METHOD_NAME = "setHostname";
private final WeakReference<Class<?>> mSSLSocketClassRef;
private final WeakReference<Method> mSetHostnameMethodRef;
/**
* Private constructor, class is a singleton.
*
* @param sslSocketClass Underlying implementation class of {@link SSLSocket} used to connect with the server.
* @param setHostnameMethod Name of the method to call to enable the SNI support.
*/
private ServerNameIndicator(Class<?> sslSocketClass, Method setHostnameMethod) {
mSSLSocketClassRef = new WeakReference<Class<?>>(sslSocketClass);
mSetHostnameMethodRef = (setHostnameMethod == null) ? null : new WeakReference<Method>(setHostnameMethod);
}
/**
* Calls the {@code #setHostname(String)} method of the underlying implementation
* of {@link SSLSocket} if exists.
* <p>
* Creates and initializes the single instance of the class when needed
*
* @param hostname The name of the server host of interest.
* @param sslSocket Client socket to connect with the server.
*/
public static void setServerNameIndication(String hostname, SSLSocket sslSocket) {
final Method setHostnameMethod = getMethod(sslSocket);
if (setHostnameMethod != null) {
try {
setHostnameMethod.invoke(sslSocket, hostname);
Log_OC.i(TAG, "SNI done, hostname: " + hostname);
} catch (IllegalArgumentException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (IllegalAccessException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
} catch (InvocationTargetException e) {
Log_OC.e(TAG, "Call to SSLSocket#setHost(String) failed ", e);
}
} else {
Log_OC.i(TAG, "SNI not supported");
}
}
/**
* Gets the method to invoke trying to minimize the effective
* application of reflection.
*
* @param sslSocket Instance of the SSL socket to use in connection with server.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method getMethod(SSLSocket sslSocket) {
final Class<?> sslSocketClass = sslSocket.getClass();
final ServerNameIndicator instance = mSingleInstance.get();
if (instance == null) {
return initFrom(sslSocketClass);
} else if (instance.mSSLSocketClassRef.get() != sslSocketClass) {
// the underlying class changed
return initFrom(sslSocketClass);
} else if (instance.mSetHostnameMethodRef == null) {
// SNI not supported
return null;
} else {
final Method cachedSetHostnameMethod = instance.mSetHostnameMethodRef.get();
return (cachedSetHostnameMethod == null) ? initFrom(sslSocketClass) : cachedSetHostnameMethod;
}
}
/**
* Singleton initializer.
* <p>
* Uses reflection to extract and 'cache' the method to invoke to indicate the desited host name to the server side.
*
* @param sslSocketClass Underlying class providing the implementation of {@link SSLSocket}.
* @return Method to call to indicate the server name of interest to the server.
*/
private static Method initFrom(Class<?> sslSocketClass) {
Log_OC.i(TAG, "SSLSocket implementation: " + sslSocketClass.getCanonicalName());
Method setHostnameMethod = null;
try {
setHostnameMethod = sslSocketClass.getMethod(METHOD_NAME, String.class);
} catch (SecurityException e) {
Log_OC.e(TAG, "Could not access to SSLSocket#setHostname(String) method ", e);
} catch (NoSuchMethodException e) {
Log_OC.i(TAG, "Could not find SSLSocket#setHostname(String) method - SNI not supported");
}
mSingleInstance.set(new ServerNameIndicator(sslSocketClass, setHostnameMethod));
return setHostnameMethod;
}
}

View File

@ -35,10 +35,8 @@ import java.util.Date;
import java.util.Locale;
public class WebdavUtils {
public static final SimpleDateFormat DISPLAY_DATE_FORMAT = new SimpleDateFormat(
"dd.MM.yyyy hh:mm");
private static final SimpleDateFormat DATETIME_FORMATS[] = {
private static final SimpleDateFormat[] DATETIME_FORMATS = {
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US),
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'", Locale.US),
@ -50,11 +48,11 @@ public class WebdavUtils {
};
public static Date parseResponseDate(String date) {
Date returnDate = null;
SimpleDateFormat format = null;
for (int i = 0; i < DATETIME_FORMATS.length; ++i) {
Date returnDate;
SimpleDateFormat format;
for (SimpleDateFormat datetimeFormat : DATETIME_FORMATS) {
try {
format = DATETIME_FORMATS[i];
format = datetimeFormat;
synchronized (format) {
returnDate = format.parse(date);
}
@ -82,23 +80,6 @@ public class WebdavUtils {
return encodedPath;
}
/**
* @param rawEtag
* @return
*/
public static String parseEtag(String rawEtag) {
if (rawEtag == null || rawEtag.length() == 0) {
return "";
}
if (rawEtag.endsWith("-gzip")) {
rawEtag = rawEtag.substring(0, rawEtag.length() - 5);
}
if (rawEtag.length() >= 2 && rawEtag.startsWith("\"") && rawEtag.endsWith("\"")) {
rawEtag = rawEtag.substring(1, rawEtag.length() - 1);
}
return rawEtag;
}
/**
* @param httpBaseMethod from which to get the etag
* @return etag from response
@ -120,4 +101,17 @@ public class WebdavUtils {
}
return result;
}
public static String normalizeProtocolPrefix(String url, boolean isSslConn) {
if (!url.toLowerCase().startsWith("http://") &&
!url.toLowerCase().startsWith("https://")) {
if (isSslConn) {
return "https://" + url;
} else {
return "http://" + url;
}
}
return url;
}
}

View File

@ -1,167 +0,0 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2017 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.network;
import com.owncloud.android.lib.common.utils.Log_OC;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicReference;
/**
* Enforces, if possible, a write timeout for a socket.
* <p>
* Built as a singleton.
* <p>
* Tries to hit something like this:
* https://android.googlesource.com/platform/external/conscrypt/+/lollipop-release/src/main/java/org/conscrypt/OpenSSLSocketImpl.java#1005
* <p>
* Minimizes the chances of getting stalled in PUT/POST request if the network interface is lost while
* writing the entity into the outwards sockect.
* <p>
* It happens. See https://github.com/owncloud/android/issues/1684#issuecomment-295306015
*
* @author David A. Velasco
*/
public class WriteTimeoutEnforcer {
private static final String TAG = WriteTimeoutEnforcer.class.getSimpleName();
private static final AtomicReference<WriteTimeoutEnforcer> mSingleInstance = new AtomicReference<>();
private static final String METHOD_NAME = "setSoWriteTimeout";
private final WeakReference<Class<?>> mSocketClassRef;
private final WeakReference<Method> mSetSoWriteTimeoutMethodRef;
/**
* Private constructor, class is a singleton.
*
* @param socketClass Underlying implementation class of {@link Socket} used to connect
* with the server.
* @param setSoWriteTimeoutMethod Name of the method to call to set a write timeout in the socket.
*/
private WriteTimeoutEnforcer(Class<?> socketClass, Method setSoWriteTimeoutMethod) {
mSocketClassRef = new WeakReference<Class<?>>(socketClass);
mSetSoWriteTimeoutMethodRef =
(setSoWriteTimeoutMethod == null) ?
null :
new WeakReference<>(setSoWriteTimeoutMethod)
;
}
/**
* Calls the {@code #setSoWrite(int)} method of the underlying implementation
* of {@link Socket} if exists.
* <p>
* Creates and initializes the single instance of the class when needed
*
* @param writeTimeoutMilliseconds Write timeout to set, in milliseconds.
* @param socket Client socket to connect with the server.
*/
public static void setSoWriteTimeout(int writeTimeoutMilliseconds, Socket socket) {
final Method setSoWriteTimeoutMethod = getMethod(socket);
if (setSoWriteTimeoutMethod != null) {
try {
setSoWriteTimeoutMethod.invoke(socket, writeTimeoutMilliseconds);
Log_OC.i(
TAG,
"Write timeout set in socket, writeTimeoutMilliseconds: "
+ writeTimeoutMilliseconds
);
} catch (IllegalArgumentException e) {
Log_OC.e(TAG, "Call to (SocketImpl)#setSoWriteTimeout(int) failed ", e);
} catch (IllegalAccessException e) {
Log_OC.e(TAG, "Call to (SocketImpl)#setSoWriteTimeout(int) failed ", e);
} catch (InvocationTargetException e) {
Log_OC.e(TAG, "Call to (SocketImpl)#setSoWriteTimeout(int) failed ", e);
}
} else {
Log_OC.i(TAG, "Write timeout for socket not supported");
}
}
/**
* Gets the method to invoke trying to minimize the cost of reflection reusing objects cached
* in static members.
*
* @param socket Instance of the socket to use in connection with server.
* @return Method to call to set a write timeout in the socket.
*/
private static Method getMethod(Socket socket) {
final Class<?> socketClass = socket.getClass();
final WriteTimeoutEnforcer instance = mSingleInstance.get();
if (instance == null) {
return initFrom(socketClass);
} else if (instance.mSocketClassRef.get() != socketClass) {
// the underlying class changed
return initFrom(socketClass);
} else if (instance.mSetSoWriteTimeoutMethodRef == null) {
// method not supported
return null;
} else {
final Method cachedSetSoWriteTimeoutMethod = instance.mSetSoWriteTimeoutMethodRef.get();
return (cachedSetSoWriteTimeoutMethod == null) ?
initFrom(socketClass) :
cachedSetSoWriteTimeoutMethod
;
}
}
/**
* Singleton initializer.
* <p>
* Uses reflection to extract and 'cache' the method to invoke to set a write timouet in a socket.
*
* @param socketClass Underlying class providing the implementation of {@link Socket}.
* @return Method to call to set a write timeout in the socket.
*/
private static Method initFrom(Class<?> socketClass) {
Log_OC.i(TAG, "Socket implementation: " + socketClass.getCanonicalName());
Method setSoWriteTimeoutMethod = null;
try {
setSoWriteTimeoutMethod = socketClass.getMethod(METHOD_NAME, int.class);
} catch (SecurityException e) {
Log_OC.e(TAG, "Could not access to (SocketImpl)#setSoWriteTimeout(int) method ", e);
} catch (NoSuchMethodException e) {
Log_OC.i(
TAG,
"Could not find (SocketImpl)#setSoWriteTimeout(int) method - write timeout not supported"
);
}
mSingleInstance.set(new WriteTimeoutEnforcer(socketClass, setSoWriteTimeoutMethod));
return setSoWriteTimeoutMethod;
}
}

View File

@ -1,3 +1,27 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.operations;
import android.accounts.Account;
@ -9,14 +33,15 @@ import android.os.Handler;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.SingleSessionManager;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.OkHttpClient;
import timber.log.Timber;
import java.io.IOException;
public abstract class RemoteOperation<T extends Object> implements Runnable {
@SuppressWarnings("WeakerAccess")
public abstract class RemoteOperation<T> implements Runnable {
/**
* OCS API header name
@ -26,7 +51,6 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
* OCS API header value
*/
public static final String OCS_API_HEADER_VALUE = "true";
private static final String TAG = RemoteOperation.class.getSimpleName();
/**
* ownCloud account in the remote ownCloud server to operate
*/
@ -40,22 +64,22 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
/**
* Object to interact with the remote server
*/
protected OwnCloudClient mClient = null;
private OwnCloudClient mClient = null;
/**
* Object to interact with the remote server
*/
protected OkHttpClient mHttpClient = null;
private OkHttpClient mHttpClient = null;
/**
* Callback object to notify about the execution of the remote operation
*/
protected OnRemoteOperationListener mListener = null;
private OnRemoteOperationListener mListener = null;
/**
* Handler to the thread where mListener methods will be called
*/
protected Handler mListenerHandler = null;
private Handler mListenerHandler = null;
/**
* Asynchronously executes the remote operation
@ -75,12 +99,10 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
OnRemoteOperationListener listener, Handler listenerHandler) {
if (account == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL Account");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
}
if (context == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL Context");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
}
// mAccount and mContext in the runnerThread to create below
mAccount = account;
@ -106,11 +128,9 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
* the listener objects must be called.
* @return Thread were the remote operation is executed.
*/
public Thread execute(OwnCloudClient client,
OnRemoteOperationListener listener, Handler listenerHandler) {
public Thread execute(OwnCloudClient client, OnRemoteOperationListener listener, Handler listenerHandler) {
if (client == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation with a NULL OwnCloudClient");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
}
mClient = client;
if (client.getAccount() != null) {
@ -120,8 +140,7 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
if (listener == null) {
throw new IllegalArgumentException
("Trying to execute a remote operation asynchronously " +
"without a listener to notiy the result");
("Trying to execute a remote operation asynchronously without a listener to notify the result");
}
mListener = listener;
@ -134,13 +153,13 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
return runnerThread;
}
protected void grantOwnCloudClient() throws
private void grantOwnCloudClient() throws
AccountUtils.AccountNotFoundException, OperationCanceledException, AuthenticatorException, IOException {
if (mClient == null) {
if (mAccount != null && mContext != null) {
OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, mContext);
mClient = OwnCloudClientManagerFactory.getDefaultSingleton().
getClientFor(ocAccount, mContext);
mClient = SingleSessionManager.getDefaultSingleton().
getClientFor(ocAccount, mContext, SingleSessionManager.getConnectionValidator());
} else {
throw new IllegalStateException("Trying to run a remote operation " +
"asynchronously with no client and no chance to create one (no account)");
@ -177,12 +196,10 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
*/
public RemoteOperationResult<T> execute(Account account, Context context) {
if (account == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Account");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Account");
}
if (context == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"Context");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL Context");
}
mAccount = account;
mContext = context.getApplicationContext();
@ -201,8 +218,7 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
*/
public RemoteOperationResult<T> execute(OwnCloudClient client) {
if (client == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
}
mClient = client;
if (client.getAccount() != null) {
@ -224,8 +240,7 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
*/
public RemoteOperationResult<T> execute(OkHttpClient client, Context context) {
if (client == null) {
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL " +
"OwnCloudClient");
throw new IllegalArgumentException("Trying to execute a remote operation with a NULL OwnCloudClient");
}
mHttpClient = client;
mContext = context;
@ -236,9 +251,7 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
/**
* Run operation for asynchronous or synchronous 'onExecute' method.
* <p>
* Considers and performs silent refresh of account credentials if possible, and if
* {@link RemoteOperation#setSilentRefreshOfAccountCredentials(boolean)} was called with
* parameter 'true' before the execution.
* Considers and performs silent refresh of account credentials if possible
*
* @return Remote operation result
*/
@ -251,7 +264,7 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
result = run(mClient);
} catch (AccountsException | IOException e) {
Log_OC.e(TAG, "Error while trying to access to " + mAccount.name, e);
Timber.e(e, "Error while trying to access to %s", mAccount.name);
result = new RemoteOperationResult<>(e);
}
@ -269,11 +282,6 @@ public abstract class RemoteOperation<T extends Object> implements Runnable {
final RemoteOperationResult resultToSend = runOperation();
if (mAccount != null && mContext != null) {
// Save Client Cookies
AccountUtils.saveClient(mClient, mAccount, mContext);
}
if (mListenerHandler != null && mListener != null) {
mListenerHandler.post(() ->
mListener.onRemoteOperationFinish(RemoteOperation.this, resultToSend));

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -27,15 +27,16 @@ package com.owncloud.android.lib.common.operations;
import android.accounts.Account;
import android.accounts.AccountsException;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.dav4jvm.exception.DavException;
import at.bitfire.dav4jvm.exception.HttpException;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.http.HttpConstants;
import com.owncloud.android.lib.common.http.methods.HttpBaseMethod;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
import com.owncloud.android.lib.common.utils.Log_OC;
import okhttp3.Headers;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.json.JSONException;
import timber.log.Timber;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
@ -45,6 +46,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
@ -52,24 +54,26 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class RemoteOperationResult<T extends Object>
public class RemoteOperationResult<T>
implements Serializable {
/**
* Generated - should be refreshed every time the class changes!!
*/
private static final long serialVersionUID = 4968939884332372230L;
private static final String LOCATION = "location";
private static final String WWW_AUTHENTICATE = "www-authenticate";
private static final String TAG = RemoteOperationResult.class.getSimpleName();
private boolean mSuccess = false;
private int mHttpCode = -1;
private String mHttpPhrase = null;
private Exception mException = null;
private ResultCode mCode = ResultCode.UNKNOWN_ERROR;
private String mRedirectedLocation;
private ArrayList<String> mAuthenticate = new ArrayList<>();
private String mRedirectedLocation = "";
private List<String> mAuthenticate = new ArrayList<>();
private String mLastPermanentLocation = null;
private T mData = null;
/**
* Public constructor from result code.
* <p>
@ -112,6 +116,14 @@ public class RemoteOperationResult<T extends Object>
*/
public RemoteOperationResult(Exception e) {
mException = e;
//TODO: Do propper exception handling and remove this
Timber.e("---------------------------------" +
"\nCreate RemoteOperationResult from exception." +
"\n Message: %s" +
"\n Stacktrace: %s" +
"\n---------------------------------",
ExceptionUtils.getMessage(e),
ExceptionUtils.getStackTrace(e));
if (e instanceof OperationCancelledException) {
mCode = ResultCode.CANCELLED;
@ -155,7 +167,10 @@ public class RemoteOperationResult<T extends Object>
} else if (e instanceof FileNotFoundException) {
mCode = ResultCode.LOCAL_FILE_NOT_FOUND;
} else {
} else if (e instanceof ProtocolException) {
mCode = ResultCode.NETWORK_ERROR;
}
else {
mCode = ResultCode.UNKNOWN_ERROR;
}
}
@ -188,10 +203,14 @@ public class RemoteOperationResult<T extends Object>
try {
if (xmlParser.parseXMLResponse(is)) {
mCode = ResultCode.INVALID_CHARACTER_DETECT_IN_SERVER;
} else {
parseErrorMessageAndSetCode(
httpMethod.getResponseBodyAsString(),
ResultCode.SPECIFIC_BAD_REQUEST
);
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
Timber.w("Error reading exception from server: %s", e.getMessage());
// mCode stays as set in this(success, httpCode, headers)
}
}
@ -222,6 +241,10 @@ public class RemoteOperationResult<T extends Object>
httpMethod.getResponseBodyAsString(),
ResultCode.SPECIFIC_METHOD_NOT_ALLOWED
);
break;
case HttpConstants.HTTP_TOO_EARLY:
mCode = ResultCode.TOO_EARLY;
break;
default:
break;
}
@ -244,18 +267,16 @@ public class RemoteOperationResult<T extends Object>
this(httpCode, httpPhrase);
if (headers != null) {
for (Map.Entry<String, List<String>> header : headers.toMultimap().entrySet()) {
if ("location".equals(header.getKey().toLowerCase())) {
if (LOCATION.equalsIgnoreCase(header.getKey())) {
mRedirectedLocation = header.getValue().get(0);
continue;
}
if ("www-authenticate".equals(header.getKey().toLowerCase())) {
mAuthenticate.add(header.getValue().get(0).toLowerCase());
if (WWW_AUTHENTICATE.equalsIgnoreCase(header.getKey())) {
for (String value: header.getValue()) {
mAuthenticate.add(value.toLowerCase());
}
}
}
if (isIdPRedirection()) {
// overrides default ResultCode.UNKNOWN
mCode = ResultCode.UNAUTHORIZED;
}
}
@ -296,11 +317,7 @@ public class RemoteOperationResult<T extends Object>
break;
default:
mCode = ResultCode.UNHANDLED_HTTP_CODE; // UNKNOWN ERROR
Log_OC.d(TAG,
"RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " +
mHttpCode + " " + mHttpPhrase
);
Timber.d("RemoteOperationResult has processed UNHANDLED_HTTP_CODE: " + mHttpCode + " " + mHttpPhrase);
}
}
}
@ -311,21 +328,19 @@ public class RemoteOperationResult<T extends Object>
*
* @param bodyResponse okHttp response body
* @param resultCode our own custom result code
* @throws IOException
*/
private void parseErrorMessageAndSetCode(String bodyResponse, ResultCode resultCode) {
if (bodyResponse != null && bodyResponse.length() > 0) {
InputStream is = new ByteArrayInputStream(bodyResponse.getBytes());
ErrorMessageParser xmlParser = new ErrorMessageParser();
try {
String errorMessage = xmlParser.parseXMLResponse(is);
if (errorMessage != "" && errorMessage != null) {
if (!errorMessage.equals("")) {
mCode = resultCode;
mHttpPhrase = errorMessage;
}
} catch (Exception e) {
Log_OC.w(TAG, "Error reading exception from server: " + e.getMessage());
Timber.w("Error reading exception from server: %s\nTrace: %s", e.getMessage(), ExceptionUtils.getStackTrace(e));
// mCode stays as set in this(success, httpCode, headers)
}
}
@ -379,7 +394,7 @@ public class RemoteOperationResult<T extends Object>
previousCause = cause;
cause = cause.getCause();
}
if (cause != null && cause instanceof CertificateCombinedException) {
if (cause instanceof CertificateCombinedException) {
result = (CertificateCombinedException) cause;
}
return result;
@ -491,12 +506,6 @@ public class RemoteOperationResult<T extends Object>
return mRedirectedLocation;
}
public boolean isIdPRedirection() {
return (mRedirectedLocation != null &&
(mRedirectedLocation.toUpperCase().contains("SAML") ||
mRedirectedLocation.toLowerCase().contains("wayf")));
}
/**
* Checks if is a non https connection
*
@ -506,7 +515,7 @@ public class RemoteOperationResult<T extends Object>
return (mRedirectedLocation != null && !(mRedirectedLocation.toLowerCase().startsWith("https://")));
}
public ArrayList<String> getAuthenticateHeaders() {
public List<String> getAuthenticateHeaders() {
return mAuthenticate;
}
@ -581,6 +590,9 @@ public class RemoteOperationResult<T extends Object>
SERVICE_UNAVAILABLE,
SPECIFIC_SERVICE_UNAVAILABLE,
SPECIFIC_UNSUPPORTED_MEDIA_TYPE,
SPECIFIC_METHOD_NOT_ALLOWED
SPECIFIC_METHOD_NOT_ALLOWED,
SPECIFIC_BAD_REQUEST,
TOO_EARLY,
NETWORK_ERROR,
}
}

View File

@ -0,0 +1,29 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.utils
fun Any.isOneOf(vararg values: Any): Boolean {
return this in values
}

View File

@ -1,212 +0,0 @@
package com.owncloud.android.lib.common.utils;
import android.util.Log;
import com.owncloud.android.lib.BuildConfig;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Locale;
public class Log_OC {
private static final String SIMPLE_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss";
private static final String LOG_FOLDER_NAME = "log";
private static final long MAX_FILE_SIZE = 2000000; // 2MB
private static String mOwncloudDataFolderLog = "owncloud_log";
private static File mLogFile;
private static File mFolder;
private static BufferedWriter mBuf;
private static String[] mLogFileNames = {
"currentLog" + BuildConfig.BUILD_TYPE + ".txt",
"olderLog" + BuildConfig.BUILD_TYPE + ".txt"
};
private static boolean isMaxFileSizeReached = false;
private static boolean isEnabled = false;
public static void setLogDataFolder(String logFolder) {
mOwncloudDataFolderLog = logFolder;
}
public static void i(String TAG, String message) {
Log.i(TAG, message);
appendLog("I: " + TAG + " : " + message);
}
public static void d(String TAG, String message) {
Log.d(TAG, message);
appendLog("D: " + TAG + " : " + message);
}
public static void d(String TAG, String message, Exception e) {
Log.d(TAG, message, e);
appendLog("D: " + TAG + " : " + message + " Exception : " + e.getStackTrace());
}
public static void e(String TAG, String message) {
Log.e(TAG, message);
appendLog("E: " + TAG + " : " + message);
}
public static void e(String TAG, String message, Throwable e) {
Log.e(TAG, message, e);
appendLog("E: " + TAG + " : " + message + " Exception : " + e.getStackTrace());
}
public static void v(String TAG, String message) {
Log.v(TAG, message);
appendLog("V: " + TAG + " : " + message);
}
public static void w(String TAG, String message) {
Log.w(TAG, message);
appendLog("W: " + TAG + " : " + message);
}
/**
* Start doing logging
*
* @param storagePath : directory for keeping logs
*/
synchronized public static void startLogging(String storagePath) {
String logPath = storagePath + File.separator + mOwncloudDataFolderLog + File.separator + LOG_FOLDER_NAME;
mFolder = new File(logPath);
mLogFile = new File(mFolder + File.separator + mLogFileNames[0]);
boolean isFileCreated = false;
if (!mFolder.exists()) {
mFolder.mkdirs();
isFileCreated = true;
Log.d("LOG_OC", "Log file created");
}
try {
// Create the current log file if does not exist
mLogFile.createNewFile();
mBuf = new BufferedWriter(new FileWriter(mLogFile, true));
isEnabled = true;
if (isFileCreated) {
appendPhoneInfo();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (mBuf != null) {
try {
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
synchronized public static void stopLogging() {
try {
if (mBuf != null) {
mBuf.close();
}
isEnabled = false;
mLogFile = null;
mFolder = null;
mBuf = null;
isMaxFileSizeReached = false;
} catch (IOException e) {
// Because we are stopping logging, we only log to Android console.
Log.e("OC_Log", "Closing log file failed: ", e);
} catch (Exception e) {
// This catch should never fire because we do null check on mBuf.
// But just for the sake of stability let's log this odd situation.
// Because we are stopping logging, we only log to Android console.
Log.e("OC_Log", "Stopping logging failed: ", e);
}
}
/**
* Delete history logging
*/
public static void deleteHistoryLogging() {
File folderLogs = new File(mFolder + File.separator);
if (folderLogs.isDirectory()) {
String[] myFiles = folderLogs.list();
for (String fileName : myFiles) {
File fileInFolder = new File(folderLogs, fileName);
Log_OC.d("delete file", fileInFolder.getAbsoluteFile() + " " + fileInFolder.delete());
}
}
}
/**
* Append the info of the device
*/
private static void appendPhoneInfo() {
appendLog("Model : " + android.os.Build.MODEL);
appendLog("Brand : " + android.os.Build.BRAND);
appendLog("Product : " + android.os.Build.PRODUCT);
appendLog("Device : " + android.os.Build.DEVICE);
appendLog("Version-Codename : " + android.os.Build.VERSION.CODENAME);
appendLog("Version-Release : " + android.os.Build.VERSION.RELEASE);
}
/**
* Append to the log file the info passed
*
* @param text : text for adding to the log file
*/
synchronized private static void appendLog(String text) {
if (isEnabled) {
if (isMaxFileSizeReached) {
// Move current log file info to another file (old logs)
File olderFile = new File(mFolder + File.separator + mLogFileNames[1]);
if (mLogFile.exists()) {
mLogFile.renameTo(olderFile);
}
// Construct a new file for current log info
mLogFile = new File(mFolder + File.separator + mLogFileNames[0]);
isMaxFileSizeReached = false;
}
String timeStamp = new SimpleDateFormat(SIMPLE_DATE_FORMAT, Locale.ENGLISH).format(Calendar.getInstance().getTime());
try {
mBuf = new BufferedWriter(new FileWriter(mLogFile, true));
mBuf.newLine();
mBuf.write(timeStamp + " " + text);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
mBuf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Check if current log file size is bigger than the max file size defined
if (mLogFile.length() > MAX_FILE_SIZE) {
isMaxFileSizeReached = true;
}
}
}
public static String[] getLogFileNames() {
return mLogFileNames;
}
}

View File

@ -0,0 +1,48 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2022 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.common.utils
import info.hannes.timber.FileLoggingTree
import info.hannes.timber.fileLoggingTree
import timber.log.Timber
import java.io.File
object LoggingHelper {
fun startLogging(directory: File, storagePath: String) {
fileLoggingTree()?.let {
Timber.uproot(it)
}
if (!directory.exists())
directory.mkdirs()
Timber.plant(FileLoggingTree(directory, filename = storagePath))
}
fun stopLogging() {
fileLoggingTree()?.let {
Timber.uproot(it)
}
}
}

View File

@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,6 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2019 ownCloud GmbH.
*
* Copyright (C) 2020 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -19,36 +20,33 @@
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources
package com.owncloud.android.lib.common.http.interceptors;
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import okhttp3.Request;
// Response retrieved by OCS Rest API, used to obtain capabilities, shares and user info among others.
// More info: https://doc.owncloud.com/server/developer_manual/core/apis/ocs-capabilities.html
@JsonClass(generateAdapter = true)
data class CommonOcsResponse<T>(
val ocs: OCSResponse<T>
)
/**
* Intercept requests to update their headers
*/
public class RequestHeaderInterceptor implements HttpInterceptor.RequestInterceptor {
@JsonClass(generateAdapter = true)
data class OCSResponse<T>(
val meta: MetaData,
val data: T?
)
private String mHeaderName;
private String mHeaderValue;
public RequestHeaderInterceptor(String headerName, String headerValue) {
this.mHeaderName = headerName;
this.mHeaderValue = headerValue;
}
@Override
public Request intercept(Request request) {
return request.newBuilder().addHeader(mHeaderName, mHeaderValue).build();
}
public String getHeaderName() {
return mHeaderName;
}
public String getHeaderValue() {
return mHeaderValue;
}
}
@JsonClass(generateAdapter = true)
data class MetaData(
val status: String,
@Json(name = "statuscode")
val statusCode: Int,
val message: String?,
@Json(name = "itemsperpage")
val itemsPerPage: String?,
@Json(name = "totalitems")
val totalItems: String?
)

View File

@ -0,0 +1,37 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2022 ownCloud GmbH.
*
* @author David González Verdugo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources
import com.owncloud.android.lib.common.OwnCloudClient
/**
* Facade to perform network calls without the verbosity of remote operations
*/
interface Service {
val client: OwnCloudClient
}

View File

@ -0,0 +1,108 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2023 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.appregistry
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
import com.owncloud.android.lib.common.network.WebdavUtils
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
import com.squareup.moshi.Json
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import okhttp3.FormBody
import okhttp3.RequestBody
import timber.log.Timber
import java.net.URL
import java.util.concurrent.TimeUnit
class CreateRemoteFileWithAppProviderOperation(
private val createFileWithAppProviderEndpoint: String,
private val parentContainerId: String,
private val filename: String,
) : RemoteOperation<String>() {
override fun run(client: OwnCloudClient): RemoteOperationResult<String> {
return try {
val createFileWithAppProviderRequestBody = CreateFileWithAppProviderParams(parentContainerId, filename)
.toRequestBody()
val stringUrl = client.baseUri.toString() + WebdavUtils.encodePath(createFileWithAppProviderEndpoint)
val postMethod = PostMethod(URL(stringUrl), createFileWithAppProviderRequestBody).apply {
setReadTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
setConnectionTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
}
val status = client.executeHttpMethod(postMethod)
Timber.d("Create file $filename with app provider in folder with ID $parentContainerId - $status${if (!isSuccess(status)) "(FAIL)" else ""}")
if (isSuccess(status)) RemoteOperationResult<String>(ResultCode.OK).apply {
val moshi = Moshi.Builder().build()
val adapter: JsonAdapter<CreateFileWithAppProviderResponse> = moshi.adapter(CreateFileWithAppProviderResponse::class.java)
data = postMethod.getResponseBodyAsString()?.let { adapter.fromJson(it)!!.fileId }
}
else RemoteOperationResult<String>(postMethod).apply { data = "" }
} catch (e: Exception) {
val result = RemoteOperationResult<String>(e)
Timber.e(e, "Create file $filename with app provider in folder with ID $parentContainerId failed")
result
}
}
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
data class CreateFileWithAppProviderParams(
val parentContainerId: String,
val filename: String,
) {
fun toRequestBody(): RequestBody =
FormBody.Builder()
.add(PARAM_PARENT_CONTAINER_ID, parentContainerId)
.add(PARAM_FILENAME, filename)
.build()
companion object {
const val PARAM_PARENT_CONTAINER_ID = "parent_container_id"
const val PARAM_FILENAME = "filename"
}
}
@JsonClass(generateAdapter = true)
data class CreateFileWithAppProviderResponse(
@Json(name = "file_id")
val fileId: String,
)
companion object {
private const val TIMEOUT: Long = 5_000
}
}

View File

@ -0,0 +1,78 @@
/* ownCloud Android Library is available under MIT license
* @author Abel García de Prada
*
* Copyright (C) 2023 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.appregistry
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
import com.owncloud.android.lib.resources.appregistry.responses.AppRegistryResponse
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import timber.log.Timber
import java.net.URL
class GetRemoteAppRegistryOperation(private val appUrl: String?) : RemoteOperation<AppRegistryResponse>() {
override fun run(client: OwnCloudClient): RemoteOperationResult<AppRegistryResponse> {
var result: RemoteOperationResult<AppRegistryResponse>
try {
val uriBuilder = client.baseUri.buildUpon().apply {
appendEncodedPath(appUrl)
}
val getMethod = GetMethod(URL(uriBuilder.build().toString()))
val status = client.executeHttpMethod(getMethod)
val response = getMethod.getResponseBodyAsString()
if (status == HttpConstants.HTTP_OK) {
Timber.d("Successful response $response")
// Parse the response
val moshi: Moshi = Moshi.Builder().build()
val adapter: JsonAdapter<AppRegistryResponse> = moshi.adapter(AppRegistryResponse::class.java)
val appRegistryResponse: AppRegistryResponse = response?.let { adapter.fromJson(it) } ?: AppRegistryResponse(value = emptyList())
result = RemoteOperationResult(OK)
result.data = appRegistryResponse
Timber.d("Get AppRegistry completed and parsed to ${result.data}")
} else {
result = RemoteOperationResult(getMethod)
Timber.e("Failed response while getting app registry from the server status code: $status; response message: $response")
}
} catch (e: Exception) {
result = RemoteOperationResult(e)
Timber.e(e, "Exception while getting app registry")
}
return result
}
}

View File

@ -0,0 +1,107 @@
/* ownCloud Android Library is available under MIT license
* Copyright (C) 2023 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.appregistry
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.http.HttpConstants
import com.owncloud.android.lib.common.http.methods.nonwebdav.PostMethod
import com.owncloud.android.lib.common.network.WebdavUtils
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonClass
import com.squareup.moshi.Moshi
import okhttp3.FormBody
import okhttp3.RequestBody
import timber.log.Timber
import java.net.URL
import java.util.concurrent.TimeUnit
class GetUrlToOpenInWebRemoteOperation(
private val openWithWebEndpoint: String,
private val fileId: String,
private val appName: String,
) : RemoteOperation<String>() {
override fun run(client: OwnCloudClient): RemoteOperationResult<String> {
return try {
val openInWebRequestBody = OpenInWebParams(fileId, appName).toRequestBody()
val stringUrl =
client.baseUri.toString() + WebdavUtils.encodePath(openWithWebEndpoint)
val postMethod = PostMethod(URL(stringUrl), openInWebRequestBody).apply {
setReadTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
setConnectionTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
}
val status = client.executeHttpMethod(postMethod)
Timber.d("Open in web for file: $fileId - $status${if (!isSuccess(status)) "(FAIL)" else ""}")
if (isSuccess(status)) RemoteOperationResult<String>(ResultCode.OK).apply {
val moshi = Moshi.Builder().build()
val adapter: JsonAdapter<OpenInWebResponse> = moshi.adapter(OpenInWebResponse::class.java)
data = postMethod.getResponseBodyAsString()?.let { adapter.fromJson(it)!!.uri }
}
else RemoteOperationResult<String>(postMethod).apply { data = "" }
} catch (e: Exception) {
val result = RemoteOperationResult<String>(e)
Timber.e(e, "Open in web for file: $fileId failed")
result
}
}
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
data class OpenInWebParams(
val fileId: String,
val appName: String,
) {
fun toRequestBody(): RequestBody =
FormBody.Builder()
.add(PARAM_FILE_ID, fileId)
.add(PARAM_APP_NAME, appName)
.build()
companion object {
const val PARAM_FILE_ID = "file_id"
const val PARAM_APP_NAME = "app_name"
}
}
@JsonClass(generateAdapter = true)
data class OpenInWebResponse(val uri: String)
companion object {
/**
* Maximum time to wait for a response from the server in milliseconds.
*/
private const val TIMEOUT = 5_000L
}
}

View File

@ -0,0 +1,56 @@
/* ownCloud Android Library is available under MIT license
* @author Abel García de Prada
*
* Copyright (C) 2023 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
package com.owncloud.android.lib.resources.appregistry.responses
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class AppRegistryResponse(
@Json(name = "mime-types")
val value: List<AppRegistryMimeTypeResponse>
)
@JsonClass(generateAdapter = true)
data class AppRegistryMimeTypeResponse(
@Json(name = "mime_type") val mimeType: String,
val ext: String? = null,
@Json(name = "app_providers")
val appProviders: List<AppRegistryProviderResponse>,
val name: String? = null,
val icon: String? = null,
val description: String? = null,
@Json(name = "allow_creation")
val allowCreation: Boolean? = null,
@Json(name = "default_application")
val defaultApplication: String? = null
)
@JsonClass(generateAdapter = true)
data class AppRegistryProviderResponse(
val name: String,
val icon: String,
)

Some files were not shown because too many files have changed in this diff Show More