Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
Aud 792 tiktok oauth (#95)
Browse files Browse the repository at this point in the history
* Update deps to fix build

* Add .env.dev to .gitignore

* Update readme

* Set up tiktok oauth

* Get TikTok sharing working e2e

* Fix canceling of auth

* Fix styling of close button

* Bump builds (#96)

Co-authored-by: Raymond Jacobson <ray@audius.co>
  • Loading branch information
sliptype and raymondjacobson authored Jul 30, 2021
1 parent 4ca3b7a commit c2b347c
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 66 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled true

versionCode 114
versionName "1.0.86"
versionCode 115
versionName "1.0.87"
resValue "string", "build_config_package", "co.audius.app"
}
productFlavors {
Expand Down
16 changes: 8 additions & 8 deletions ios/AudiusReactNative.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -410,13 +410,13 @@
BUNDLE_ID_SUFFIX = "";
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "AudiusReactNative/Audius Music.entitlements";
CURRENT_PROJECT_VERSION = 172;
CURRENT_PROJECT_VERSION = 173;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = LRFCG93S85;
INFOPLIST_FILE = AudiusReactNative/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0.75;
MARKETING_VERSION = 1.0.76;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand All @@ -442,12 +442,12 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "AudiusReactNative/Audius Music.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 172;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = LRFCG93S85;
INFOPLIST_FILE = AudiusReactNative/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0.75;
MARKETING_VERSION = 1.0.76;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -630,13 +630,13 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "AudiusReactNative/Audius Music.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 172;
CURRENT_PROJECT_VERSION = 173;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = LRFCG93S85;
INFOPLIST_FILE = AudiusReactNative/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0.75;
MARKETING_VERSION = 1.0.76;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down Expand Up @@ -710,12 +710,12 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = "AudiusReactNative/Audius Music.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 172;
CURRENT_PROJECT_VERSION = 173;
DEVELOPMENT_TEAM = LRFCG93S85;
INFOPLIST_FILE = AudiusReactNative/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0.75;
MARKETING_VERSION = 1.0.76;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
Expand Down
2 changes: 1 addition & 1 deletion ios/AudiusReactNative/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>172</string>
<string>173</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
Expand Down
161 changes: 107 additions & 54 deletions src/components/oauth/OAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,25 @@ import {
getUrl,
getIsOpen,
getMessageId,
getAuthProvider
getAuthProvider,
getMessageType
} from '../../store/oauth/selectors'
import { AppState } from '../../store'
import { closePopup } from '../../store/oauth/actions'
import { Provider } from '../../store/oauth/reducer'
import { WebViewMessage } from 'react-native-webview/lib/WebViewTypes'
import { MessageType } from '../../message'
import { MessagePostingWebView } from '../../types/MessagePostingWebView'
import { postMessage } from '../../utils/postMessage'

const AUTH_RESPONSE = 'auth-response'

const TWITTER_POLLER = `
(function() {
const exit = () => {
window.ReactNativeWebView.postMessage(
JSON.stringify({})
JSON.stringify({
type: 'auth-response'
})
)
}
Expand All @@ -41,6 +45,7 @@ const TWITTER_POLLER = `
window.ReactNativeWebView.postMessage(
JSON.stringify({
type: 'auth-response',
oauthToken,
oauthVerifier
})
Expand All @@ -62,7 +67,9 @@ const INSTAGRAM_POLLER = `
(function() {
const exit = () => {
window.ReactNativeWebView.postMessage(
JSON.stringify({})
JSON.stringify({
type: 'auth-response'
})
)
}
Expand All @@ -78,7 +85,10 @@ const INSTAGRAM_POLLER = `
if (!instagramCode) exit()
window.ReactNativeWebView.postMessage(
JSON.stringify({ instagramCode })
JSON.stringify({
type: 'auth-response',
instagramCode
})
)
} else {
exit()
Expand All @@ -93,6 +103,45 @@ const INSTAGRAM_POLLER = `
})();
`

const TIKTOK_POLLER = `
(function() {
const exit = () => {
window.ReactNativeWebView.postMessage(
JSON.stringify({
type: 'auth-response'
})
)
}
setInterval(() => {
try {
if (
!window.location.hostname.includes('tiktok.com')
) {
const query = new URLSearchParams(window.location.search || '')
const authorizationCode = query.get('code')
const csrfState = query.get('state')
const error = query.get('error')
if (authorizationCode && csrfState) {
window.ReactNativeWebView.postMessage(
JSON.stringify({
type: 'auth-response',
authorizationCode,
csrfState,
})
)
} else {
exit()
}
}
} catch {
exit()
}
}, 500)
})();
`

type OwnProps = {
webRef: RefObject<MessagePostingWebView>
}
Expand All @@ -101,61 +150,69 @@ type Props = OwnProps &
ReturnType<typeof mapStateToProps> &
ReturnType<typeof mapDispatchToProps>

const OAuth = ({ url, isOpen, messageId, webRef, provider, close }: Props) => {
const OAuth = ({
url,
isOpen,
messageId,
messageType,
webRef,
provider,
close
}: Props) => {
// Handle messages coming from the web view
const onMessageHandler = (event: NativeSyntheticEvent<WebViewMessage>) => {
if (event.nativeEvent.data && webRef.current) {
const message = JSON.parse(event.nativeEvent.data)
if (provider === Provider.TWITTER) {
if (message.oauthToken && message.oauthVerifier) {
postMessage(webRef.current, {
type: MessageType.REQUEST_TWITTER_AUTH,
id: messageId,
oauthToken: message.oauthToken,
oauthVerifier: message.oauthVerifier
})
} else {
postMessage(webRef.current, {
type: MessageType.REQUEST_TWITTER_AUTH,
id: messageId
})
}
} else if (provider === Provider.INSTAGRAM) {
if (message.instagramCode) {
postMessage(webRef.current, {
type: MessageType.REQUEST_INSTAGRAM_AUTH,
id: messageId,
code: message.instagramCode
})
} else {
postMessage(webRef.current, {
type: MessageType.REQUEST_INSTAGRAM_AUTH,
id: messageId
})
const data = JSON.parse(event.nativeEvent.data)

if (data.type === AUTH_RESPONSE) {
const payloadByProvider = {
[Provider.TWITTER]: (message: any) =>
message.oauthToken && message.oauthVerifier
? {
oauthToken: message.oauthToken,
oauthVerifier: message.oauthVerifier
}
: {},
[Provider.INSTAGRAM]: (message: any) =>
message.instagramCode
? {
code: message.instagramCode
}
: {},
[Provider.TIKTOK]: (message: any) =>
message.authorizationCode && message.csrfState
? {
authorizationCode: message.authorizationCode,
csrfState: message.csrfState
}
: {}
}

postMessage(webRef.current, {
type: messageType,
id: messageId,
...payloadByProvider[provider as Provider](data)
})
close()
}
}
close()
}
const onClose = useCallback(() => {
if (provider === Provider.TWITTER && webRef.current) {
postMessage(webRef.current, {
type: MessageType.REQUEST_TWITTER_AUTH,
id: messageId
})
}

if (provider === Provider.INSTAGRAM && webRef.current) {
if (webRef.current) {
postMessage(webRef.current, {
type: MessageType.REQUEST_INSTAGRAM_AUTH,
type: messageType,
id: messageId
})
}
close()
}, [webRef, messageId, close, provider])
}, [webRef, messageId, messageType, close])

const injected = {
[Provider.TWITTER]: TWITTER_POLLER,
[Provider.INSTAGRAM]: INSTAGRAM_POLLER,
[Provider.TIKTOK]: TIKTOK_POLLER
}[provider as Provider]

const injected =
provider === Provider.INSTAGRAM ? INSTAGRAM_POLLER : TWITTER_POLLER
return (
<Modal
animationType='slide'
Expand All @@ -164,16 +221,11 @@ const OAuth = ({ url, isOpen, messageId, webRef, provider, close }: Props) => {
presentationStyle='overFullScreen'
hardwareAccelerated
>
<View style={{ flex: 1, marginTop: 20 }}>
<View style={{ flex: 1, marginTop: 40 }}>
<View
style={{
height: 40,
flexDirection: 'row',
justifyContent: 'flex-start',
paddingTop: 6,
paddingLeft: 6,
paddingBottom: 6,
marginTop: 10
width: 75,
marginLeft: 8
}}
>
<Button onPress={onClose} title='Close' />
Expand All @@ -194,6 +246,7 @@ const mapStateToProps = (state: AppState) => ({
url: getUrl(state),
isOpen: getIsOpen(state),
messageId: getMessageId(state),
messageType: getMessageType(state),
provider: getAuthProvider(state)
})

Expand Down
3 changes: 3 additions & 0 deletions src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export enum MessageType {
// OAuth
REQUEST_TWITTER_AUTH = 'request-twitter-auth',
REQUEST_INSTAGRAM_AUTH = 'request-instagram-auth',
REQUEST_TIKTOK_AUTH = 'request-tiktok-auth',

// Lifecycle
ENTER_FOREGROUND = 'action/enter-foreground',
Expand Down Expand Up @@ -251,6 +252,8 @@ export const handleMessage = async (
return dispatch(oauthActions.openPopup(message, Provider.TWITTER))
case MessageType.REQUEST_INSTAGRAM_AUTH:
return dispatch(oauthActions.openPopup(message, Provider.INSTAGRAM))
case MessageType.REQUEST_TIKTOK_AUTH:
return dispatch(oauthActions.openPopup(message, Provider.TIKTOK))

// Lifecycle
case MessageType.BACKEND_SETUP:
Expand Down
8 changes: 7 additions & 1 deletion src/store/oauth/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
import { MessageType } from 'message'
import { OAuthActions, OPEN_POPUP, CLOSE_POPUP } from './actions'

export type OAuthState = {
isOpen: boolean
// Incoming message id to reply back to with OAuth results
messageId: string | null
messageType: MessageType | null
url: string | null
provider: Provider | null
}

export enum Provider {
TWITTER = 'TWITTER',
INSTAGRAM = 'INSTAGRAM'
INSTAGRAM = 'INSTAGRAM',
TIKTOK = 'TIKTOK'
}

const initialState: OAuthState = {
isOpen: false,
messageId: null,
messageType: null,
url: null,
provider: null
}
Expand All @@ -30,6 +34,7 @@ const reducer = (
...state,
isOpen: true,
messageId: action.message.id,
messageType: action.message.type,
url: action.message.authURL,
provider: action.provider
}
Expand All @@ -38,6 +43,7 @@ const reducer = (
...state,
isOpen: false,
messageId: null,
messageType: null,
url: null,
provider: null
}
Expand Down
2 changes: 2 additions & 0 deletions src/store/oauth/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ const getBaseState = (state: AppState) => state.oauth
export const getIsOpen = (state: AppState) => getBaseState(state).isOpen
export const getUrl = (state: AppState) => getBaseState(state).url
export const getMessageId = (state: AppState) => getBaseState(state).messageId
export const getMessageType = (state: AppState) =>
getBaseState(state).messageType
export const getAuthProvider = (state: AppState) => getBaseState(state).provider

0 comments on commit c2b347c

Please sign in to comment.