From 82166cedff46e38ae3be081cdc0b0752457d3b6d Mon Sep 17 00:00:00 2001 From: bocops Date: Tue, 12 Dec 2023 13:19:20 +0100 Subject: [PATCH] Enable hierarchical access to defined scopes - replace Name enum with hierarchical structure for a more intuitive access to individual scopes - changing samples and USAGE.md to match Examples: - Scope(Scope.Name.READ) becomes Scope(Scope.READ.ALL) - Scope(Scope.Name.ADMIN_READ_ACCOUNTS) becomes Scope(Scope.ADMIN.READ.ACCOUNTS) --- USAGE.md | 8 +- .../kotlin/social/bigbone/TestConstants.kt | 5 +- .../main/kotlin/social/bigbone/api/Scope.kt | 455 ++++++++++++------ .../bigbone/api/method/OAuthMethodsTest.kt | 2 +- .../kotlin/social/bigbone/entity/ScopeTest.kt | 8 +- .../social/bigbone/sample/Authenticator.java | 2 +- .../bigbone/sample/GetAppRegistration.java | 2 +- .../bigbone/sample/OAuthGetAccessToken.java | 2 +- .../social/bigbone/sample/Authenticator.kt | 2 +- .../bigbone/sample/OAuthGetAccessToken.kt | 2 +- 10 files changed, 332 insertions(+), 156 deletions(-) diff --git a/USAGE.md b/USAGE.md index 2c15a4635..17cac3e07 100644 --- a/USAGE.md +++ b/USAGE.md @@ -22,9 +22,9 @@ Additionally, this guide uses the following values that should be replaced in yo // The actual value used instead should be a URL that will be interpreted by your application. redirectUris = "urn:ietf:wg:oauth:2.0:oob" -// This is equal to the full range of scopes currently supported by BigBone. +// This is equal to the full range of non-admin scopes currently supported by BigBone. // Instead of this, you should request as little as possible for your application. -scope = Scope() +fullScope = Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL) ``` ## Registering an App @@ -46,7 +46,7 @@ val client: MastodonClient = MastodonClient.Builder(instanceHostname).build() val appRegistration = client.apps.createApp( clientName = "bigbone-sample-app", redirectUris = "urn:ietf:wg:oauth:2.0:oob", - scope = Scope(), + scope = fullScope, website = "https://example.org/" ).execute() ``` @@ -64,7 +64,7 @@ try { AppRegistration appRegistration=client.apps().createApp( "bigbone-sample-app", "urn:ietf:wg:oauth:2.0:oob", - new Scope(), + fullScope, "https://example.org/" ).execute(); } catch (BigBoneRequestException e) { diff --git a/bigbone/src/integrationTest/kotlin/social/bigbone/TestConstants.kt b/bigbone/src/integrationTest/kotlin/social/bigbone/TestConstants.kt index aee4fb0a9..3c7262c62 100644 --- a/bigbone/src/integrationTest/kotlin/social/bigbone/TestConstants.kt +++ b/bigbone/src/integrationTest/kotlin/social/bigbone/TestConstants.kt @@ -18,9 +18,6 @@ class TestConstants { const val USER2_EMAIL = "user2@email.dev" const val USER2_PASSWORD = "user2abcdef" - /** - * This scope should allow accessing all non-admin endpoints in integration tests. - */ - val fullScope = Scope(Scope.Name.READ, Scope.Name.WRITE, Scope.Name.PUSH) + val fullScope = Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL) } } diff --git a/bigbone/src/main/kotlin/social/bigbone/api/Scope.kt b/bigbone/src/main/kotlin/social/bigbone/api/Scope.kt index bccee1679..38f650a54 100644 --- a/bigbone/src/main/kotlin/social/bigbone/api/Scope.kt +++ b/bigbone/src/main/kotlin/social/bigbone/api/Scope.kt @@ -1,259 +1,438 @@ package social.bigbone.api /** - * Represents the access permissions that can be requested when registering an app or when - * requesting access tokens. + * Represents the access permissions that can be requested when registering an app or when requesting access tokens. + * Existing scopes are available via members of this class, arranged hierarchically. It is recommended that you request + * as little as possible for your application. * @param scopes individual scopes that should be requested. + * @see Mastodon OAuth scopes */ +@Suppress("UseDataClass") // data class can not be used with primary constructor vararg parameters class Scope(private vararg val scopes: Name) { /** - * The available scopes. These scopes are hierarchical, i.e. if you have access to [READ], you automatically have - * access to [READ_ACCOUNTS]. It is recommended that you request as little as possible for your application. + * Interface to define scopes. While existing Mastodon scopes are generally available as objects of the [Scope] + * class, potential new scopes defined by Mastodon but not yet implemented here can be added by using this interface. */ - enum class Name(val scopeName: String) { + interface Name { + val name: String + } + + /** + * Scopes granting access to read data are grouped here. Use [READ.ALL] to request full read access, or preferably + * individual child scopes to limit access to a minimum. + */ + object READ { + /** - * Grants access to read data. Requesting this scope will also grant its child scopes. + * Grants access to read all data. Requesting this scope is equivalent to requesting all other [READ] child scopes. */ - READ("read"), + @JvmField + val ALL = object : Name { + override val name: String + get() = "read" + } /** * Child scope of [READ]. */ - READ_ACCOUNTS("read:accounts"), + @JvmField + val ACCOUNTS = object : Name { + override val name: String get() = "read:accounts" + } /** * Child scope of [READ]. */ - READ_BLOCKS("read:blocks"), + @JvmField + val BLOCKS = object : Name { + override val name: String get() = "read:blocks" + } /** * Child scope of [READ]. */ - READ_BOOKMARKS("read:bookmarks"), + @JvmField + val BOOKMARKS = object : Name { + override val name: String get() = "read:bookmarks" + } /** * Child scope of [READ]. */ - READ_FAVOURITES("read:favourites"), + @JvmField + val FAVOURITES = object : Name { + override val name: String get() = "read:favourites" + } /** * Child scope of [READ]. */ - READ_FILTERS("read:filters"), + @JvmField + val FILTERS = object : Name { + override val name: String get() = "read:filters" + } /** * Child scope of [READ]. */ - READ_FOLLOWS("read:follows"), + @JvmField + val FOLLOWS = object : Name { + override val name: String get() = "read:follows" + } /** * Child scope of [READ]. */ - READ_LISTS("read:lists"), + @JvmField + val LISTS = object : Name { + override val name: String get() = "read:lists" + } /** * Child scope of [READ]. */ - READ_MUTES("read:mutes"), + @JvmField + val MUTES = object : Name { + override val name: String get() = "read:mutes" + } /** * Child scope of [READ]. */ - READ_NOTIFICATIONS("read:notifications"), + @JvmField + val NOTIFICATIONS = object : Name { + override val name: String get() = "read:notifications" + } /** * Child scope of [READ]. */ - READ_SEARCH("read:search"), + @JvmField + val SEARCH = object : Name { + override val name: String get() = "read:search" + } /** * Child scope of [READ]. */ - READ_STATUSES("read:statuses"), + @JvmField + val STATUSES = object : Name { + override val name: String get() = "read:statuses" + } + } - /** - * Grants access to write data. Requesting this scope will also grant its child scopes - */ - WRITE("write"), + /** + * Scopes granting access to write data are grouped here. Use [WRITE.ALL] to request full write access, or preferably + * individual child scopes to limit access to a minimum. + */ + object WRITE { /** - * Child scope of [WRITE]. + * Grants access to write all data. Requesting this scope is equivalent to requesting all other child scopes. */ - WRITE_ACCOUNTS("write:accounts"), + @JvmField + val ALL = object : Name { + override val name: String + get() = "write" + } /** * Child scope of [WRITE]. */ - WRITE_BLOCKS("write:blocks"), + @JvmField + val ACCOUNTS = object : Name { + override val name: String get() = "write:accounts" + } /** * Child scope of [WRITE]. */ - WRITE_BOOKMARKS("write:bookmarks"), + @JvmField + val BLOCKS = object : Name { + override val name: String get() = "write:blocks" + } /** * Child scope of [WRITE]. */ - WRITE_CONVERSATIONS("write:conversations"), + @JvmField + val BOOKMARKS = object : Name { + override val name: String get() = "write:bookmarks" + } /** * Child scope of [WRITE]. */ - WRITE_FAVOURITES("write:favourites"), + @JvmField + val CONVERSATIONS = object : Name { + override val name: String get() = "write:conversations" + } /** * Child scope of [WRITE]. */ - WRITE_FILTERS("write:filters"), + @JvmField + val FAVOURITES = object : Name { + override val name: String get() = "write:favourites" + } /** * Child scope of [WRITE]. */ - WRITE_FOLLOWS("write:follows"), + @JvmField + val FILTERS = object : Name { + override val name: String get() = "write:filters" + } /** * Child scope of [WRITE]. */ - WRITE_LISTS("write:lists"), + @JvmField + val FOLLOWS = object : Name { + override val name: String get() = "write:follows" + } /** * Child scope of [WRITE]. */ - WRITE_MEDIA("write:media"), + @JvmField + val LISTS = object : Name { + override val name: String get() = "write:lists" + } /** * Child scope of [WRITE]. */ - WRITE_MUTES("write:mutes"), + @JvmField + val MEDIA = object : Name { + override val name: String get() = "write:media" + } /** * Child scope of [WRITE]. */ - WRITE_NOTIFICATIONS("write:notifications"), + @JvmField + val MUTES = object : Name { + override val name: String get() = "write:mutes" + } /** * Child scope of [WRITE]. */ - WRITE_REPORTS("write:reports"), + @JvmField + val NOTIFICATIONS = object : Name { + override val name: String get() = "write:notifications" + } /** * Child scope of [WRITE]. */ - WRITE_STATUSES("write:statuses"), - - /** - * Grants access to Web Push API subscriptions. - */ - PUSH("push"), + @JvmField + val REPORTS = object : Name { + override val name: String get() = "write:reports" + } /** - * Used for moderation API. Requesting this scope will also grant its child scopes. - */ - ADMIN_READ("admin:read"), - - /** - * Child scope of [ADMIN_READ]. - */ - ADMIN_READ_ACCOUNTS("admin:read:accounts"), - - /** - * Child scope of [ADMIN_READ]. - */ - ADMIN_READ_REPORTS("admin:read:reports"), - - /** - * Child scope of [ADMIN_READ]. - */ - ADMIN_READ_DOMAIN_ALLOWS("admin:read:domain_allows"), - - /** - * Child scope of [ADMIN_READ]. - */ - ADMIN_READ_DOMAIN_BLOCKS("admin:read:domain_blocks"), - - /** - * Child scope of [ADMIN_READ]. - */ - ADMIN_READ_IP_BLOCKS("admin:read:ip_blocks"), - - /** - * Child scope of [ADMIN_READ]. - */ - ADMIN_READ_EMAIL_DOMAIN_BLOCKS("admin:read:email_domain_blocks"), - - /** - * Child scope of [ADMIN_READ]. - */ - ADMIN_READ_CANONICAL_EMAIL_BLOCKS("admin:read:canonical_email_blocks"), - - /** - * Used for moderation API. Requesting this scope will also grant its child scopes. - */ - ADMIN_WRITE("admin:write"), - - /** - * Child scope of [ADMIN_WRITE]. - */ - ADMIN_WRITE_ACCOUNTS("admin:write:accounts"), - - /** - * Child scope of [ADMIN_WRITE]. - */ - ADMIN_WRITE_REPORTS("admin:write:reports"), - - /** - * Child scope of [ADMIN_WRITE]. - */ - ADMIN_WRITE_DOMAIN_ALLOWS("admin:write:domain_allows"), - - /** - * Child scope of [ADMIN_WRITE]. - */ - ADMIN_WRITE_DOMAIN_BLOCKS("admin:write:domain_blocks"), - - /** - * Child scope of [ADMIN_WRITE]. + * Child scope of [WRITE]. */ - ADMIN_WRITE_IP_BLOCKS("admin:write:ip_blocks"), + @JvmField + val STATUSES = object : Name { + override val name: String get() = "write:statuses" + } + } - /** - * Child scope of [ADMIN_WRITE]. - */ - ADMIN_WRITE_EMAIL_DOMAIN_BLOCKS("admin:write:email_domain_blocks"), + /** + * Scopes granting access to Web Push API subscriptions are grouped here. Currently, only [PUSH.ALL] exists. + */ + object PUSH { /** - * Child scope of [ADMIN_WRITE]. + * Grants access to Web Push API subscriptions. */ - ADMIN_WRITE_CANONICAL_EMAIL_BLOCKS("admin:write:canonical_email_blocks"), + @JvmField + val ALL = object : Name { + override val name: String get() = "push" + } + } - /** - * Grants access to manage relationships. Requesting this scope will also grant the child scopes - * [READ_BLOCKS], [WRITE_BLOCKS], [READ_FOLLOWS], [WRITE_FOLLOWS], [READ_MUTES] and [WRITE_MUTES]. - */ - @Deprecated( - message = "Deprecated since Mastodon 3.5.0 and will be removed in the future. Use child scopes of READ and WRITE instead.", - level = DeprecationLevel.WARNING - ) - FOLLOW("follow"), + /** + * Scopes granting access to the moderation API are grouped here, split between [ADMIN.READ] and [ADMIN.WRITE] for + * read and write access, respectively. + */ + object ADMIN { + + /** + * Scopes granting read access to the moderation API are grouped here. Use [ADMIN.READ.ALL] to request full + * read access, or preferably individual child scopes to limit access to a minimum. + */ + object READ { + + /** + * Grants read access to the moderation API. Requesting this scope is equivalent to requesting all other + * child scopes. + */ + @JvmField + val ALL = object : Name { + override val name: String get() = "admin:read" + } + + /** + * Child scope of [ADMIN.READ]. + */ + @JvmField + val ACCOUNTS = object : Name { + override val name: String get() = "admin:read:accounts" + } + + /** + * Child scope of [ADMIN.READ]. + */ + @JvmField + val REPORTS = object : Name { + override val name: String get() = "admin:read:reports" + } + + /** + * Child scope of [ADMIN.READ]. + */ + @JvmField + val DOMAIN_ALLOWS = object : Name { + override val name: String get() = "admin:read:domain_allows" + } + + /** + * Child scope of [ADMIN.READ]. + */ + @JvmField + val DOMAIN_BLOCKS = object : Name { + override val name: String get() = "admin:read:domain_blocks" + } + + /** + * Child scope of [ADMIN.READ]. + */ + @JvmField + val IP_BLOCKS = object : Name { + override val name: String get() = "admin:read:ip_blocks" + } + + /** + * Child scope of [ADMIN.READ]. + */ + @JvmField + val EMAIL_DOMAIN_BLOCKS = object : Name { + override val name: String get() = "admin:read:email_domain_blocks" + } + + /** + * Child scope of [ADMIN.READ]. + */ + @JvmField + val CANONICAL_EMAIL_BLOCKS = object : Name { + override val name: String get() = "admin:read:canonical_email_blocks" + } + } + + /** + * Scopes granting write access to the moderation API are grouped here. Use [ADMIN.WRITE.ALL] to request full + * write access, or preferably individual child scopes to limit access to a minimum. + */ + object WRITE { + + /** + * Grants write access to the moderation API. Requesting this scope is equivalent to requesting all other + * child scopes. + */ + @JvmField + val ALL = object : Name { + override val name: String get() = "admin:write" + } + + /** + * Child scope of [ADMIN.WRITE]. + */ + @JvmField + val ACCOUNTS = object : Name { + override val name: String get() = "admin:write:accounts" + } + + /** + * Child scope of [ADMIN.WRITE]. + */ + @JvmField + val REPORTS = object : Name { + override val name: String get() = "admin:write:reports" + } + + /** + * Child scope of [ADMIN.WRITE]. + */ + @JvmField + val DOMAIN_ALLOWS = object : Name { + override val name: String get() = "admin:write:domain_allows" + } + + /** + * Child scope of [ADMIN.WRITE]. + */ + @JvmField + val DOMAIN_BLOCKS = object : Name { + override val name: String get() = "admin:write:domain_blocks" + } + + /** + * Child scope of [ADMIN.WRITE]. + */ + @JvmField + val IP_BLOCKS = object : Name { + override val name: String get() = "admin:write:ip_blocks" + } + + /** + * Child scope of [ADMIN.WRITE]. + */ + @JvmField + val EMAIL_DOMAIN_BLOCKS = object : Name { + override val name: String get() = "admin:write:email_domain_blocks" + } + + /** + * Child scope of [ADMIN.WRITE]. + */ + @JvmField + val CANONICAL_EMAIL_BLOCKS = object : Name { + override val name: String get() = "admin:write:canonical_email_blocks" + } + } + } - /** - * Grants full non-admin access by requesting the top-level scopes [READ], [WRITE] and [FOLLOW]. - * It is recommended that you request as little as possible for your application, so consider using individual - * scopes instead. - */ - @Deprecated( - message = "Includes FOLLOW scope deprecated since Mastodon 3.5.0, and will be removed in the future. " + - "If necessary, switch to requesting all top-level scopes directly.", - replaceWith = ReplaceWith("Scope(PUSH, READ, WRITE)"), - level = DeprecationLevel.WARNING - ) - ALL(Scope(READ, WRITE, FOLLOW).toString()) + /** + * Grants access to manage relationships. Requesting this scope will also grant the child scopes + * [READ.BLOCKS], [WRITE.BLOCKS], [READ.FOLLOWS], [WRITE.FOLLOWS], [READ.MUTES] and [WRITE.MUTES]. + */ + @Deprecated( + message = "Deprecated since Mastodon 3.5.0 and will be removed in the future. Use child scopes of READ and WRITE instead.", + level = DeprecationLevel.WARNING + ) + object FOLLOW : Name { + override val name: String get() = "follow" } - fun validate() { - require(scopes.size == scopes.distinct().size) { "There is a duplicate scope. : $this" } + /** + * Grants full non-admin access by requesting the top-level scopes [READ], [WRITE] and [FOLLOW]. + * It is recommended that you request as little as possible for your application, so consider using individual + * scopes instead. + */ + @Deprecated( + message = "Includes FOLLOW scope deprecated since Mastodon 3.5.0, and will be removed in the future. " + + "If necessary, switch to requesting all top-level scopes directly.", + replaceWith = ReplaceWith("Scope(READ, WRITE, PUSH)"), + level = DeprecationLevel.WARNING + ) + object ALL : Name { + override val name: String get() = "read write follow" } - override fun toString(): String = scopes.distinct().joinToString(separator = " ", transform = { it.scopeName }) + override fun toString(): String = scopes.distinct().joinToString(separator = " ", transform = { it.name }) } diff --git a/bigbone/src/test/kotlin/social/bigbone/api/method/OAuthMethodsTest.kt b/bigbone/src/test/kotlin/social/bigbone/api/method/OAuthMethodsTest.kt index 92ade71e0..af7c24b98 100644 --- a/bigbone/src/test/kotlin/social/bigbone/api/method/OAuthMethodsTest.kt +++ b/bigbone/src/test/kotlin/social/bigbone/api/method/OAuthMethodsTest.kt @@ -27,7 +27,7 @@ class OAuthMethodsTest { val url = OAuthMethods(client).getOAuthUrl( clientId = "client_id", redirectUri = TestConstants.REDIRECT_URI, - scope = Scope(Scope.Name.READ, Scope.Name.WRITE_ACCOUNTS, Scope.Name.ADMIN_READ_REPORTS) + scope = Scope(Scope.READ.ALL, Scope.WRITE.ACCOUNTS, Scope.ADMIN.READ.REPORTS) ) url shouldBeEqualTo "https://mastodon.cloud/oauth/authorize?client_id=client_id" + diff --git a/bigbone/src/test/kotlin/social/bigbone/entity/ScopeTest.kt b/bigbone/src/test/kotlin/social/bigbone/entity/ScopeTest.kt index 1ae81828a..fc63a39ca 100644 --- a/bigbone/src/test/kotlin/social/bigbone/entity/ScopeTest.kt +++ b/bigbone/src/test/kotlin/social/bigbone/entity/ScopeTest.kt @@ -7,14 +7,14 @@ import social.bigbone.api.Scope class ScopeTest { @Test fun toStringTest() { - Scope(Scope.Name.READ).toString() shouldBeEqualTo "read" - Scope(Scope.Name.READ, Scope.Name.WRITE).toString() shouldBeEqualTo "read write" + Scope(Scope.READ.ALL).toString() shouldBeEqualTo "read" + Scope(Scope.READ.ALL, Scope.WRITE.ALL).toString() shouldBeEqualTo "read write" Scope().toString() shouldBeEqualTo "" } @Test fun toStringTestWithDuplicates() { - Scope(Scope.Name.READ, Scope.Name.READ).toString() shouldBeEqualTo "read" - Scope(Scope.Name.READ, Scope.Name.WRITE, Scope.Name.PUSH, Scope.Name.WRITE).toString() shouldBeEqualTo "read write push" + Scope(Scope.READ.ALL, Scope.READ.ALL).toString() shouldBeEqualTo "read" + Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL, Scope.WRITE.ALL).toString() shouldBeEqualTo "read write push" } } diff --git a/sample-java/src/main/java/social/bigbone/sample/Authenticator.java b/sample-java/src/main/java/social/bigbone/sample/Authenticator.java index 33cbf3b41..46df3ff1b 100644 --- a/sample-java/src/main/java/social/bigbone/sample/Authenticator.java +++ b/sample-java/src/main/java/social/bigbone/sample/Authenticator.java @@ -19,7 +19,7 @@ final class Authenticator { private static final String ACCESS_TOKEN = "access_token"; private static final String REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob"; - private static final Scope FULL_SCOPE = new Scope(Scope.Name.READ, Scope.Name.WRITE, Scope.Name.PUSH); + private static final Scope FULL_SCOPE = new Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL); private Authenticator() { } diff --git a/sample-java/src/main/java/social/bigbone/sample/GetAppRegistration.java b/sample-java/src/main/java/social/bigbone/sample/GetAppRegistration.java index e7a5d01f8..40aeb4bbb 100644 --- a/sample-java/src/main/java/social/bigbone/sample/GetAppRegistration.java +++ b/sample-java/src/main/java/social/bigbone/sample/GetAppRegistration.java @@ -13,7 +13,7 @@ public static void main(final String[] args) throws BigBoneRequestException { "bigbone-sample-app", "urn:ietf:wg:oauth:2.0:oob", "", - new Scope(Scope.Name.READ, Scope.Name.WRITE, Scope.Name.PUSH) + new Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL) ).execute(); System.out.println("client_id=" + application.getClientId()); System.out.println("client_secret=" + application.getClientSecret()); diff --git a/sample-java/src/main/java/social/bigbone/sample/OAuthGetAccessToken.java b/sample-java/src/main/java/social/bigbone/sample/OAuthGetAccessToken.java index d2d95f5bc..73b2a297e 100644 --- a/sample-java/src/main/java/social/bigbone/sample/OAuthGetAccessToken.java +++ b/sample-java/src/main/java/social/bigbone/sample/OAuthGetAccessToken.java @@ -16,7 +16,7 @@ public static void main(final String[] args) throws BigBoneRequestException { final String redirectUri = args[3]; final MastodonClient client = new MastodonClient.Builder(instanceName).build(); - final Scope fullScope = new Scope(Scope.Name.READ, Scope.Name.WRITE, Scope.Name.PUSH); + final Scope fullScope = new Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL); final String url = client.oauth().getOAuthUrl(clientId, redirectUri, fullScope); System.out.println("Open authorization page and copy code:"); System.out.println(url); diff --git a/sample-kotlin/src/main/kotlin/social/bigbone/sample/Authenticator.kt b/sample-kotlin/src/main/kotlin/social/bigbone/sample/Authenticator.kt index 006eab426..457101f00 100644 --- a/sample-kotlin/src/main/kotlin/social/bigbone/sample/Authenticator.kt +++ b/sample-kotlin/src/main/kotlin/social/bigbone/sample/Authenticator.kt @@ -13,7 +13,7 @@ object Authenticator { private const val CLIENT_SECRET = "client_secret" private const val ACCESS_TOKEN = "access_token" private const val REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob" - private val fullScope = Scope(Scope.Name.READ, Scope.Name.WRITE, Scope.Name.PUSH) + private val fullScope = Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL) fun appRegistrationIfNeeded(instanceName: String, credentialFilePath: String, useStreaming: Boolean = false): MastodonClient { val file = File(credentialFilePath) diff --git a/sample-kotlin/src/main/kotlin/social/bigbone/sample/OAuthGetAccessToken.kt b/sample-kotlin/src/main/kotlin/social/bigbone/sample/OAuthGetAccessToken.kt index fa5ecdace..47d42288a 100644 --- a/sample-kotlin/src/main/kotlin/social/bigbone/sample/OAuthGetAccessToken.kt +++ b/sample-kotlin/src/main/kotlin/social/bigbone/sample/OAuthGetAccessToken.kt @@ -14,7 +14,7 @@ object OAuthGetAccessToken { val clientSecret = args[2] val redirectUri = args[3] val client = MastodonClient.Builder(instanceName).build() - val fullScope = Scope(Scope.Name.READ, Scope.Name.WRITE, Scope.Name.PUSH) + val fullScope = Scope(Scope.READ.ALL, Scope.WRITE.ALL, Scope.PUSH.ALL) val url = client.oauth.getOAuthUrl(clientId, redirectUri, fullScope) println("Open authorization page and copy code:") println(url)