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