mirror of
				https://github.com/owncloud/android-library.git
				synced 2025-10-31 02:17:41 +00:00 
			
		
		
		
	Merge pull request #481 from owncloud/feature/webfinger
add moshi classes for webfinger responses
This commit is contained in:
		
						commit
						376d52ac5b
					
				| @ -0,0 +1,108 @@ | |||||||
|  | /* 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.resources.webfinger | ||||||
|  | 
 | ||||||
|  | import android.net.Uri | ||||||
|  | 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.http.methods.nonwebdav.HttpMethod | ||||||
|  | import com.owncloud.android.lib.common.operations.RemoteOperation | ||||||
|  | import com.owncloud.android.lib.common.operations.RemoteOperationResult | ||||||
|  | import com.owncloud.android.lib.resources.webfinger.responses.WebfingerJrdResponse | ||||||
|  | import com.squareup.moshi.Moshi | ||||||
|  | import timber.log.Timber | ||||||
|  | import java.net.URL | ||||||
|  | 
 | ||||||
|  | class GetOCInstanceViaWebfingerOperation( | ||||||
|  |     private val lockupServerDomain: String, | ||||||
|  |     private val rel: String, | ||||||
|  |     private val resource: String, | ||||||
|  | ) : RemoteOperation<String>() { | ||||||
|  | 
 | ||||||
|  |     private fun buildRequestUri() = | ||||||
|  |         Uri.parse(lockupServerDomain).buildUpon() | ||||||
|  |             .path(ENDPOINT_WEBFINGER_PATH) | ||||||
|  |             .appendQueryParameter("rel", rel) | ||||||
|  |             .appendQueryParameter("resource", resource) | ||||||
|  |             .build() | ||||||
|  | 
 | ||||||
|  |     private fun isSuccess(status: Int): Boolean = status == HttpConstants.HTTP_OK | ||||||
|  | 
 | ||||||
|  |     private fun parseResponse(response: String): WebfingerJrdResponse { | ||||||
|  |         val moshi = Moshi.Builder().build() | ||||||
|  |         val adapter = moshi.adapter(WebfingerJrdResponse::class.java) | ||||||
|  |         return adapter.fromJson(response)!! | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun onResultUnsuccessful( | ||||||
|  |         method: HttpMethod, | ||||||
|  |         response: String?, | ||||||
|  |         status: Int | ||||||
|  |     ): RemoteOperationResult<String> { | ||||||
|  |         Timber.e("Failed requesting webfinger info") | ||||||
|  |         if (response != null) { | ||||||
|  |             Timber.e("*** status code: $status; response message: $response") | ||||||
|  |         } else { | ||||||
|  |             Timber.e("*** status code: $status") | ||||||
|  |         } | ||||||
|  |         return RemoteOperationResult<String>(method) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun onRequestSuccessful(rawResponse: String): RemoteOperationResult<String> { | ||||||
|  |         val response = parseResponse(rawResponse) | ||||||
|  |         for (i in response.links) { | ||||||
|  |             if (i.rel == rel) { | ||||||
|  |                 val operationResult = RemoteOperationResult<String>(RemoteOperationResult.ResultCode.OK) | ||||||
|  |                 operationResult.data = i.href | ||||||
|  |                 return operationResult | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Timber.e("Could not find ownCloud relevant information in webfinger response: $rawResponse") | ||||||
|  |         throw java.lang.Exception("Could not find ownCloud relevant information in webfinger response") | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     override fun run(client: OwnCloudClient): RemoteOperationResult<String> { | ||||||
|  |         val requestUri = buildRequestUri() | ||||||
|  |         val getMethod = GetMethod(URL(requestUri.toString())) | ||||||
|  |         return try { | ||||||
|  |             val status = client.executeHttpMethod(getMethod) | ||||||
|  |             val response = getMethod.getResponseBodyAsString()!! | ||||||
|  | 
 | ||||||
|  |             if (isSuccess(status)) { | ||||||
|  |                 onRequestSuccessful(response) | ||||||
|  |             } else { | ||||||
|  |                 onResultUnsuccessful(getMethod, response, status) | ||||||
|  |             } | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             Timber.e(e, "Requesting webfinger info failed") | ||||||
|  |             RemoteOperationResult<String>(e) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private const val ENDPOINT_WEBFINGER_PATH = "/.well-known/webfinger" | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,39 @@ | |||||||
|  | /* 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.resources.webfinger.responses | ||||||
|  | 
 | ||||||
|  | import com.squareup.moshi.JsonClass | ||||||
|  | 
 | ||||||
|  | @JsonClass(generateAdapter = true) | ||||||
|  | data class WebfingerJrdResponse( | ||||||
|  |     val subject: String, | ||||||
|  |     val links: List<LinkItem> | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | @JsonClass(generateAdapter = true) | ||||||
|  | data class LinkItem( | ||||||
|  |     val href: String, | ||||||
|  |     val rel: String | ||||||
|  | ) | ||||||
| @ -0,0 +1,29 @@ | |||||||
|  | /** | ||||||
|  |  * ownCloud Android client application | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2022 ownCloud GmbH. | ||||||
|  |  * | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  | package com.owncloud.android.lib.resources.webfinger.services | ||||||
|  | 
 | ||||||
|  | import com.owncloud.android.lib.common.OwnCloudClient | ||||||
|  | import com.owncloud.android.lib.common.operations.RemoteOperationResult | ||||||
|  | 
 | ||||||
|  | interface WebfingerService { | ||||||
|  |     fun getInstanceFromWebfinger( | ||||||
|  |         lookupServer: String, | ||||||
|  |         username: String, | ||||||
|  |         client: OwnCloudClient, | ||||||
|  |     ): RemoteOperationResult<String> | ||||||
|  | } | ||||||
| @ -0,0 +1,38 @@ | |||||||
|  | /** | ||||||
|  |  * ownCloud Android client application | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2022 ownCloud GmbH. | ||||||
|  |  * | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  * This program is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||||
|  |  */ | ||||||
|  | package com.owncloud.android.lib.resources.webfinger.services.implementation | ||||||
|  | 
 | ||||||
|  | import com.owncloud.android.lib.common.OwnCloudClient | ||||||
|  | import com.owncloud.android.lib.common.operations.RemoteOperationResult | ||||||
|  | import com.owncloud.android.lib.resources.webfinger.GetOCInstanceViaWebfingerOperation | ||||||
|  | import com.owncloud.android.lib.resources.webfinger.services.WebfingerService | ||||||
|  | 
 | ||||||
|  | class OCWebfingerService : WebfingerService { | ||||||
|  | 
 | ||||||
|  |     override fun getInstanceFromWebfinger( | ||||||
|  |         lookupServer: String, | ||||||
|  |         username: String, | ||||||
|  |         client: OwnCloudClient, | ||||||
|  |     ): RemoteOperationResult<String> = | ||||||
|  |         GetOCInstanceViaWebfingerOperation(lookupServer, OWNCLOUD_REL, username).execute(client) | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private const val OWNCLOUD_REL = "http://webfinger.owncloud/rel/server-instance" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -0,0 +1,49 @@ | |||||||
|  | package com.owncloud.android.lib.resources.webfinger.responses | ||||||
|  | 
 | ||||||
|  | import com.squareup.moshi.JsonAdapter | ||||||
|  | import com.squareup.moshi.JsonDataException | ||||||
|  | import com.squareup.moshi.Moshi | ||||||
|  | import org.junit.Assert | ||||||
|  | import org.junit.Before | ||||||
|  | import org.junit.Test | ||||||
|  | import java.io.File | ||||||
|  | 
 | ||||||
|  | class WebfingerResponseTest { | ||||||
|  |     lateinit var adapter: JsonAdapter<WebfingerJrdResponse> | ||||||
|  | 
 | ||||||
|  |     private fun loadResponses(fileName: String) = adapter.fromJson(File(fileName).readText()) | ||||||
|  | 
 | ||||||
|  |     @Before | ||||||
|  |     fun prepare() { | ||||||
|  |         val moshi = Moshi.Builder().build() | ||||||
|  |         adapter = moshi.adapter(WebfingerJrdResponse::class.java) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     fun `check rel in too much information - ok`() { | ||||||
|  |         val response = loadResponses(TOO_MUCH_INFORMATION_JSON)!! | ||||||
|  |         Assert.assertEquals("https://gast.somedomain.de", response.links[0].href) | ||||||
|  |         Assert.assertEquals("http://webfinger.owncloud/rel/server-instance", response.links[0].rel) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = JsonDataException::class) | ||||||
|  |     fun `check key value pairs - ko - no href key`() { | ||||||
|  |         val response = loadResponses(BROKEN_JSON)!! | ||||||
|  |         Assert.assertEquals("https://gast.somedomain.de", response.links[0].href) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test(expected = JsonDataException::class) | ||||||
|  |     fun `check key value pairs - ko - no rel key`() { | ||||||
|  |         val response = loadResponses(BROKEN_JSON)!! | ||||||
|  |         Assert.assertEquals("https://gast.somedomain.de", response.links[0].href) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         private const val RESOURCES_PATH = | ||||||
|  |             "src/test/responses/com.owncloud.android.lib.resources.webfinger.responses" | ||||||
|  |         private const val EXAMPLE_RESPONSE_JSON = "$RESOURCES_PATH/simple_response.json" | ||||||
|  |         private const val TOO_MUCH_INFORMATION_JSON = "$RESOURCES_PATH/to_much_information_response.json" | ||||||
|  |         private const val BROKEN_JSON = "$RESOURCES_PATH/broken_response.json" | ||||||
|  |         private const val NOT_CONTAINING_RELEVANT_INFORMATION_JSON = "$RESOURCES_PATH/not_containing_relevant_info_response.json" | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | { | ||||||
|  |   "subject": "acct:bob@example.com", | ||||||
|  |   "aliases": [ | ||||||
|  |     "https://www.example.com/~bob/" | ||||||
|  |   ], | ||||||
|  |   "properties": { | ||||||
|  |     "http://example.com/ns/role": "employee" | ||||||
|  |   }, | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "lel": "http://webfinger.example/rel/profile-page", | ||||||
|  |       "foo": "https://www.example.com/~bob/" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | { | ||||||
|  |   "subject": "acct:peter.sine@gurken.xxx", | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "rel": "http://webfinger.example/rel/businesscard", | ||||||
|  |       "href": "https://www.example.com/~bob/bob.vcf" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
| @ -0,0 +1,9 @@ | |||||||
|  | { | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "href": "https://gast.somedomain.de", | ||||||
|  |       "rel": "http://webfinger.owncloud/rel/server-instance" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "subject": "acct:peter.sine@gurken.xxx" | ||||||
|  | } | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | { | ||||||
|  |   "subject": "acct:peter.sine@gurken.xxx", | ||||||
|  |   "aliases": [ | ||||||
|  |     "https://www.example.com/~bob/" | ||||||
|  |   ], | ||||||
|  |   "properties": { | ||||||
|  |     "http://example.com/ns/role": "employee" | ||||||
|  |   }, | ||||||
|  |   "gurken": { | ||||||
|  |     "whatever": 42 | ||||||
|  |   }, | ||||||
|  |   "links": [ | ||||||
|  |     { | ||||||
|  |       "gurken": "sallat", | ||||||
|  |       "href": "https://gast.somedomain.de", | ||||||
|  |       "rel": "http://webfinger.owncloud/rel/server-instance" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "gurken": "sallat", | ||||||
|  |       "rel": "http://webfinger.example/rel/businesscard", | ||||||
|  |       "href": "https://www.example.com/~bob/bob.vcf" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user