1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
|
import AsyncStorage from '@react-native-community/async-storage';
import {Alert} from 'react-native';
import InAppBrowser from 'react-native-inappbrowser-reborn';
import {
LINKED_SOCIALS_ENDPOINT,
LINK_FB_ENDPOINT,
LINK_FB_OAUTH,
LINK_IG_ENDPOINT,
LINK_IG_OAUTH,
LINK_SNAPCHAT_ENDPOINT,
LINK_TIKTOK_ENDPOINT,
LINK_TWITTER_ENDPOINT,
LINK_TWITTER_OAUTH,
} from '../constants';
import {COMING_SOON_MSG, ERROR_LINK, SUCCESS_LINK} from '../constants/strings';
// A list of endpoint strings for all the integrated socials
export const integratedEndpoints: {[social: string]: [string, string]} = {
Instagram: [LINK_IG_OAUTH, LINK_IG_ENDPOINT],
Facebook: [LINK_FB_OAUTH, LINK_FB_ENDPOINT],
Twitter: [LINK_TWITTER_OAUTH, LINK_TWITTER_ENDPOINT],
};
export const nonIntegratedEndpoints: {[social: string]: string} = {
Snapchat: LINK_SNAPCHAT_ENDPOINT,
TikTok: LINK_TIKTOK_ENDPOINT,
};
export const getNonIntegratedURL: (
socialType: string,
userId: string,
) => Promise<string> = async (socialType, userId) => {
if (!(socialType in nonIntegratedEndpoints)) {
return '';
}
try {
const userToken = await AsyncStorage.getItem('token');
const response = await fetch(
nonIntegratedEndpoints[socialType] + userId + '/',
{
method: 'GET',
headers: {
Authorization: `Token ${userToken}`,
},
},
);
if (response.status !== 200) {
throw 'Unable to fetch profile URL:' + socialType;
}
const body = await response.json();
return body.url || '';
} catch (error) {
console.log(error);
return '';
}
};
export const registerNonIntegratedSocialLink: (
socialType: string,
username: string,
) => Promise<boolean> = async (socialType, username) => {
if (!(socialType in nonIntegratedEndpoints)) {
return false;
}
try {
const user_token = await AsyncStorage.getItem('token');
const response = await fetch(nonIntegratedEndpoints[socialType], {
method: 'POST',
headers: {
Authorization: `Token ${user_token}`,
},
body: JSON.stringify({
username: username,
}),
});
return response.status === 200;
} catch (error) {
console.log(error);
return false;
}
};
// We have already received the short-lived token (callback_data), sending it
// to backend to exchange for and store the long-lived token.
export const registerIntegratedSocialLink: (
callback_data: string,
user_token: string,
socialType: string,
) => Promise<boolean> = async (callback_data, user_token, socialType) => {
if (!(socialType in integratedEndpoints)) {
return false;
}
const response = await fetch(integratedEndpoints[socialType][1], {
method: 'POST',
headers: {
Authorization: `Token ${user_token}`,
},
body: JSON.stringify({
callback_url: callback_data,
}),
});
if (!(response.status === 201)) {
console.log(await response.json());
}
return response.status === 201;
};
// Twitter is a special case since they use OAuth1, we will need to request
// for a request_token before we can begin browser signin.
export const getTwitterRequestToken: (user_token: string) => Promise<string> =
async (user_token) => {
const response = await fetch(integratedEndpoints.Twitter[0], {
method: 'GET',
headers: {
Authorization: `Token ${user_token}`,
},
});
return response.url;
};
// one stop shop for handling all browser sign-in social linkings
export const handlePressForAuthBrowser: (
socialType: string,
) => Promise<boolean> = async (socialType: string) => {
try {
if (!(socialType in integratedEndpoints)) {
Alert.alert(COMING_SOON_MSG);
return false;
}
if (!(await InAppBrowser.isAvailable())) {
// Okay... to open an external browser and have it link back to
// the app is a bit tricky, we will need to have navigation routes
// setup for this screen and have it hooked up.
// See https://github.com/proyecto26/react-native-inappbrowser#authentication-flow-using-deep-linking
// Though this isn't the end of the world, from the documentation,
// the in-app browser should be supported from iOS 11, which
// is about 98.5% of all iOS devices in the world.
// See https://support.apple.com/en-gb/HT209574
Alert.alert(
'Sorry! Your device was unable to open a browser to let you sign-in! 😔',
);
return false;
}
let url = integratedEndpoints[socialType][0];
const user_token = await AsyncStorage.getItem('token');
if (!user_token) {
throw 'Unable to get user token';
}
// We will need to do an extra step for twitter sign-in
if (socialType === 'Twitter') {
url = await getTwitterRequestToken(user_token);
}
return await InAppBrowser.openAuth(url, 'taggid://callback', {
ephemeralWebSession: true,
})
.then(async (response) => {
if (response.type === 'success' && response.url) {
const success = await registerIntegratedSocialLink(
response.url,
user_token,
socialType,
);
if (!success) {
throw 'Unable to register with backend';
}
Alert.alert(SUCCESS_LINK(socialType));
return true;
} else if (response.type === 'cancel') {
return false;
} else {
throw 'Error from Oauth API';
}
})
.catch((error) => {
console.log(error);
Alert.alert(ERROR_LINK(socialType));
return false;
});
} catch (error) {
console.log(error);
Alert.alert(ERROR_LINK(socialType));
}
return false;
};
// get all the linked socials from backend as an array
export const getLinkedSocials: (user_id: string) => Promise<string[]> = async (
user_id: string,
) => {
try {
const user_token = await AsyncStorage.getItem('token');
const response = await fetch(`${LINKED_SOCIALS_ENDPOINT}${user_id}/`, {
method: 'GET',
headers: {
Authorization: 'Token ' + user_token,
},
});
if (response.status !== 200) {
return [];
}
const body = await response.json();
return body.linked_socials || [];
} catch (error) {
console.log(error);
return [];
}
};
|