forked from Acode-Foundation/Acode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauth.js
More file actions
156 lines (136 loc) · 3.29 KB
/
auth.js
File metadata and controls
156 lines (136 loc) · 3.29 KB
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
import toast from "components/toast";
import { addIntentHandler } from "handlers/intent";
import constants from "./constants";
const loginEvents = {
listeners: new Set(),
emit(data) {
for (const listener of this.listeners) {
listener(data);
}
},
on(callback) {
this.listeners.add(callback);
},
off(callback) {
this.listeners.delete(callback);
},
};
class AuthService {
constructor() {
addIntentHandler(this.onIntentReceiver.bind(this));
}
async onIntentReceiver(event) {
try {
if (event?.module === "user" && event?.action === "login") {
if (event?.value) {
this._exec("saveToken", [event.value]);
toast("Logged in successfully");
setTimeout(() => {
loginEvents.emit();
}, 500);
}
}
return null;
} catch (error) {
console.error("Failed to parse intent token.", error);
return null;
}
}
/**
* Helper to wrap cordova.exec in a Promise
*/
_exec(action, args = []) {
return new Promise((resolve, reject) => {
cordova.exec(resolve, reject, "Authenticator", action, args);
});
}
async openLoginUrl() {
const url = `${constants.BASE_URL}/login?redirect=app`;
try {
await new Promise((resolve, reject) => {
CustomTabs.open(url, { showTitle: true }, resolve, reject);
});
} catch (error) {
console.error("CustomTabs failed, opening system browser.", error);
system.openInBrowser(url);
}
}
async logout() {
try {
await this._exec("logout");
return true;
} catch (error) {
console.error("Failed to logout.", error);
return false;
}
}
async isLoggedIn() {
try {
// Native checks EncryptedPrefs and validates with API internally
await this._exec("isLoggedIn");
return true;
} catch (error) {
console.error(error);
// error is typically the status code (0 if no token, 401 if invalid)
return false;
}
}
async getUserInfo() {
try {
const data = await this._exec("getUserInfo");
return typeof data === "string" ? JSON.parse(data) : data;
} catch (error) {
console.error("Failed to fetch user data.", error);
return null;
}
}
async getAvatar() {
try {
const userData = await this.getUserInfo();
if (!userData) return null;
if (userData.github) {
return `https://avatars.githubusercontent.com/${userData.github}`;
}
if (userData.name) {
return this._generateInitialsAvatar(userData.name);
}
return null;
} catch (error) {
console.error("Failed to get avatar", error);
return null;
}
}
_generateInitialsAvatar(name) {
const nameParts = name.split(" ");
const initials =
nameParts.length >= 2
? `${nameParts[0][0]}${nameParts[1][0]}`.toUpperCase()
: nameParts[0][0].toUpperCase();
const canvas = document.createElement("canvas");
canvas.width = 100;
canvas.height = 100;
const ctx = canvas.getContext("2d");
const colors = [
"#2196F3",
"#9C27B0",
"#E91E63",
"#009688",
"#4CAF50",
"#FF9800",
];
ctx.fillStyle =
colors[
name.split("").reduce((acc, char) => acc + char.charCodeAt(0), 0) %
colors.length
];
ctx.fillRect(0, 0, 100, 100);
ctx.fillStyle = "#ffffff";
ctx.font = "bold 40px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(initials, 50, 50);
return canvas.toDataURL();
}
}
export default new AuthService();
export { loginEvents };