@ozdao/prometheus-framework 0.1.7 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. package/dist/Breadcrumbs.vue_vue_type_style_index_0_lang-561d6db3.js +1 -0
  2. package/dist/Breadcrumbs.vue_vue_type_style_index_0_lang-9e474158.mjs +1945 -0
  3. package/dist/ButtonFollow-38d9a720.mjs +131 -0
  4. package/dist/ButtonFollow-9a33ab06.js +1 -0
  5. package/dist/CardOrganization-3049931d.mjs +230 -0
  6. package/dist/CardOrganization-8b376cbb.js +1 -0
  7. package/dist/Chips-03ff0c34.mjs +108 -0
  8. package/dist/Chips-4d8ac62e.js +1 -0
  9. package/dist/Feed-1d0d9853.js +1 -0
  10. package/dist/Feed-79839e67.mjs +368 -0
  11. package/dist/Feed-af94027c.js +1 -0
  12. package/dist/Feed-b616f102.mjs +439 -0
  13. package/dist/Image-75f5becb.js +9 -0
  14. package/dist/Image-be69af9c.mjs +477 -0
  15. package/dist/Popup-d7dbc670.mjs +76 -0
  16. package/dist/Popup-ee4bd834.js +1 -0
  17. package/dist/Product-8bee8d1c.mjs +838 -0
  18. package/dist/Product-a39f3ca3.js +7 -0
  19. package/dist/ProductEdit-052b0aef.mjs +350 -0
  20. package/dist/ProductEdit-a322f1ba.js +1 -0
  21. package/dist/ProfileBlogposts-08f784c3.mjs +64 -0
  22. package/dist/ProfileBlogposts-d6bba033.js +1 -0
  23. package/dist/ProfileComments-96f6cde8.mjs +44 -0
  24. package/dist/ProfileComments-dd923865.js +1 -0
  25. package/dist/ProfileEvents-1e0c1291.js +1 -0
  26. package/dist/ProfileEvents-26a72fe2.mjs +56 -0
  27. package/dist/ProfileLikes-b1060d1e.js +1 -0
  28. package/dist/ProfileLikes-c8dab14d.mjs +44 -0
  29. package/dist/ProfileOrganizations-3a879480.mjs +212 -0
  30. package/dist/ProfileOrganizations-78fef72e.js +1 -0
  31. package/dist/Publics-8bb9a680.js +1 -0
  32. package/dist/Publics-ffc08ad7.mjs +123 -0
  33. package/dist/UploadImage-6344f789.js +1 -0
  34. package/dist/UploadImage-f04e4bc0.mjs +83 -0
  35. package/dist/auth-60c81f40.mjs +1836 -0
  36. package/dist/auth-e8f6d979.js +8 -0
  37. package/dist/auth.client.cjs +4 -4
  38. package/dist/auth.client.js +247 -236
  39. package/dist/auth.server.js +72 -11
  40. package/dist/auth.server.mjs +72 -11
  41. package/dist/auth.validation-1d5f2990.mjs +20 -0
  42. package/dist/auth.validation-2dfb450f.js +1 -0
  43. package/dist/community.client.cjs +1 -1
  44. package/dist/community.client.js +11 -11
  45. package/dist/events.client.cjs +1 -1
  46. package/dist/events.client.js +9 -9
  47. package/dist/organizations-4157d81d.js +1 -0
  48. package/dist/organizations-52438d24.mjs +121 -0
  49. package/dist/organizations.client-16ee6b43.js +3 -0
  50. package/dist/organizations.client-cdbaf6aa.mjs +3017 -0
  51. package/dist/organizations.client.cjs +1 -1
  52. package/dist/organizations.client.js +11 -11
  53. package/dist/users.client.cjs +1 -1
  54. package/dist/users.client.js +258 -239
  55. package/dist/users.server.js +7 -0
  56. package/dist/users.server.mjs +7 -0
  57. package/package.json +2 -1
  58. package/src/components/CardHeader/CardHeader.vue +2 -1
  59. package/src/modules/auth/components/pages/SignIn.vue +48 -39
  60. package/src/modules/auth/controllers/auth.controller.js +42 -11
  61. package/src/modules/auth/store/auth.js +3 -10
  62. package/src/modules/auth/utils/server/verifyAppleIdToken.js +57 -0
  63. package/src/modules/users/components/pages/Profile.vue +20 -6
  64. package/src/modules/users/components/pages/ProfileEdit.vue +15 -5
  65. package/src/modules/users/models/user.model.js +9 -1
  66. package/src/modules/users/store/users.js +2 -1
@@ -147,7 +147,14 @@ var user_model = (mongoose) => {
147
147
  username: String,
148
148
  phone: String,
149
149
  email: String,
150
+ apple_id: String,
150
151
  password: String,
152
+ status: {
153
+ type: String,
154
+ enum: ["active", "banned", "removed"],
155
+ default: "active",
156
+ required: true
157
+ },
151
158
  profile: {
152
159
  photo: {
153
160
  type: String,
@@ -146,7 +146,14 @@ var user_model = (mongoose) => {
146
146
  username: String,
147
147
  phone: String,
148
148
  email: String,
149
+ apple_id: String,
149
150
  password: String,
151
+ status: {
152
+ type: String,
153
+ enum: ["active", "banned", "removed"],
154
+ default: "active",
155
+ required: true
156
+ },
150
157
  profile: {
151
158
  photo: {
152
159
  type: String,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ozdao/prometheus-framework",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Web3 Framework focused on user experience and ease of development.",
5
5
  "author": "OZ DAO <hello@ozdao.dev>",
6
6
  "license": "GPL-3.0-or-later",
@@ -144,6 +144,7 @@
144
144
  "@googlemaps/google-maps-services-js": "^3.3.37",
145
145
  "@intlify/unplugin-vue-i18n": "^1.0.1",
146
146
  "@vuepic/vue-datepicker": "^7.0.0",
147
+ "jwk-to-pem": "^2.0.5",
147
148
  "libphonenumber-js": "^1.10.41",
148
149
  "mongoose": "^7.5.2",
149
150
  "multer": "^1.4.5-lts.1",
@@ -50,12 +50,13 @@
50
50
  >
51
51
  {{owner.target.profile.name}}
52
52
  </span>
53
+
53
54
  <span
54
55
  v-if="!creator.hidden && owner.target.profile.name !== creator.target.profile.name"
55
56
  @click.stop="$router.push({
56
57
  name: 'User Profile',
57
58
  params: {
58
- _id: owner.target._id
59
+ _id: creator.target._id
59
60
  }
60
61
  })"
61
62
  >
@@ -12,8 +12,8 @@
12
12
  "passwordPlaceholder": "Enter your password",
13
13
  "forgotPassword": "Forgot Password?",
14
14
  "signin": "Sign In",
15
+ "signin_apple": "Sign In with Apple",
15
16
  "soon": "SOON",
16
- "signinMetamask": "Sign In with Apple"
17
17
  },
18
18
  "ru": {
19
19
  "title": "Приветствуем вас,",
@@ -27,8 +27,8 @@
27
27
  "passwordPlaceholder": "Введите ваш пароль",
28
28
  "forgotPassword": "Забыли пароль?",
29
29
  "signin": "Войти",
30
- "soon": "СКОРО",
31
- "signinMetamask": "Войти через Apple"
30
+ "signin_apple": "Войти через Apple",
31
+ "soon": "СКОРО"
32
32
  }
33
33
  }
34
34
  </i18n>
@@ -105,16 +105,29 @@
105
105
  />
106
106
  <!-- Links -->
107
107
  <div class="w-100 mn-big">
108
- <router-link to="/auth/reset-password" class="underline d-block t-blue">{{ t('forgotPassword') }}</router-link>
108
+ <router-link
109
+ to="/auth/reset-password"
110
+ class="underline d-block t-blue"
111
+ >
112
+ {{ t('forgotPassword') }}
113
+ </router-link>
109
114
  </div>
110
115
  <!-- Button -->
111
- <Button :submit="onSubmit" :callback="redirectTo" class="mn-thin">{{ t('signin') }}</Button>
112
-
113
- <button @click="appleSignIn" class="bg-black t-white w-100 button">
114
- <div class=" flex-v-center flex">
115
- <span class="mn-r-small">{{ t('signinMetamask') }}</span>
116
- </div>
117
- </button>
116
+ <Button
117
+ :submit="onSubmit"
118
+ :callback="redirectTo"
119
+ class="mn-thin"
120
+ >
121
+ {{ t('signin') }}
122
+ </Button>
123
+
124
+ <Button
125
+ :submit="onSubmitApple"
126
+ :callback="redirectTo"
127
+ class="mn-thin bg-black t-white"
128
+ >
129
+ {{ t('signin_apple') }}
130
+ </Button>
118
131
  </section>
119
132
  </template>
120
133
 
@@ -150,32 +163,6 @@ const tabAuth = ref('phone')
150
163
  const clientId = inject('APPLE_CLIENTID')
151
164
  const redirectURI = inject('APPLE_REDIRECT_URL')
152
165
 
153
- const appleSignIn = async () => {
154
-
155
- window.AppleID.auth.init({
156
- clientId: clientId,
157
- scope: 'email name',
158
- redirectURI: redirectURI,
159
- usePopup: true,
160
- });
161
- /** Signin to appleID */
162
- return window.AppleID.auth
163
- .signIn()
164
- .then((response) => {
165
- /** This is only called in case usePopup is true */
166
- if (response) {
167
- console.log(response)
168
- }
169
- /** resolve with the reponse */
170
- return response;
171
- })
172
- .catch((err) => {
173
- /** Log the error to help debug */
174
- console.error(err);
175
- return null;
176
- });
177
- };
178
-
179
166
  const loadExternalScript = (src) => {
180
167
  return new Promise((resolve, reject) => {
181
168
  const script = document.createElement('script');
@@ -211,6 +198,29 @@ async function onSubmit() {
211
198
  await auth.actions.login(auth.state.user, tabAuth.value)
212
199
  }
213
200
 
201
+ async function onSubmitApple() {
202
+ try {
203
+ window.AppleID.auth.init({
204
+ clientId: clientId,
205
+ scope: 'email name',
206
+ redirectURI: redirectURI,
207
+ usePopup: true,
208
+ });
209
+
210
+ let response = await window.AppleID.auth.signIn();
211
+
212
+ if (response) {
213
+ console.log(response);
214
+ await auth.actions.login(response, 'apple');
215
+ }
216
+
217
+ } catch (error) {
218
+ console.error(error);
219
+ throw new Error('Error during Apple authentication');
220
+ }
221
+ }
222
+
223
+
214
224
  function redirectTo () {
215
225
  router.push({ name: 'User Profile', params: { _id: auth.state.user._id }})
216
226
  }
@@ -251,5 +261,4 @@ function redirectTo () {
251
261
  border: 1px solid red;
252
262
  box-shadow: 0 0 3px 0 red;
253
263
  }
254
-
255
- </style>
264
+ </style>
@@ -2,17 +2,21 @@ const jwt = require("jsonwebtoken");
2
2
  const bcrypt = require("bcryptjs");
3
3
  const ObjectId = require('mongoose').Types.ObjectId;
4
4
  const { uuid } = require('uuidv4');
5
-
5
+ // Utils
6
+ const { verifyAppleIdToken } = require('../utils/server/verifyAppleIdToken')
7
+ // Factory
6
8
  const controllerFactory = (db) => {
9
+
7
10
  const User = db.user;
8
11
  const Membership = db.membership;
9
12
  const Invite = db.invite;
10
13
  const Role = db.role;
11
14
 
12
15
  const signin = async (req, res) => {
13
- const { type, email, phone } = req.body;
16
+ const { type, email, phone, authorization } = req.body;
14
17
 
15
18
  let query;
19
+ let payload = null;
16
20
 
17
21
  if (type === 'phone' && phone) {
18
22
  query = { phone };
@@ -22,18 +26,45 @@ const controllerFactory = (db) => {
22
26
  query = { email };
23
27
  }
24
28
 
29
+ if (type === 'apple' && authorization.id_token) {
30
+
31
+ payload = await verifyAppleIdToken(authorization.id_token);
32
+
33
+ if (payload) {
34
+ query = { apple_id: payload.sub };
35
+ } else {
36
+ return res.status(401).send({ errorCode: "INVALID_APPLE_ID_TOKEN" });
37
+ }
38
+ }
39
+
25
40
  try {
26
- const user = await User.findOne(query).populate('roles').exec();
27
-
28
- if (!user) {
29
- return res.status(404).send({ errorCode: "USER_PHONE_OR_PASSWORD_NOT_FOUND" });
41
+
42
+ let user = await User.findOne(query).populate('roles').exec();
43
+
44
+ if ((type === 'email' || type === 'phone') && req.body.password) {
45
+
46
+ const passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
47
+
48
+ if (!passwordIsValid) {
49
+ return res.status(401).send({ errorCode: "INCORRECT_PASSWORD_ENTERED", accessToken: null });
50
+ }
30
51
  }
31
-
32
- const passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
33
-
34
- if (!passwordIsValid) {
35
- return res.status(401).send({ errorCode: "INCORRECT_PASSWORD_ENTERED", accessToken: null });
52
+
53
+ if (type === 'apple' && !user) {
54
+ const { firstName, lastName } = req.body.user.name;
55
+
56
+ const newUser = new User({
57
+ apple_id: payload.sub,
58
+ email: payload.email,
59
+ profile: { name: `${firstName} ${lastName}` },
60
+ });
61
+
62
+ await newUser.save();
63
+ user = newUser;
64
+ } else if (!user) {
65
+ return res.status(404).send({ errorCode: "USER_NOT_FOUND" });
36
66
  }
67
+
37
68
  const memberships = await Membership.findOne({ user: user._id });
38
69
 
39
70
  const token = jwt.sign({
@@ -46,21 +46,13 @@
46
46
  const actions = {
47
47
  async login (user, type) {
48
48
  try {
49
-
50
- console.log(user.phone.number)
51
-
52
49
  const response = await $axios.post('/api/auth/signin', {
53
- email: user.email,
54
- phone: user.phone.number,
55
- password: user.password,
56
- passwordRepeat: '',
50
+ ...user,
57
51
  type
58
52
  })
59
53
 
60
54
  setCookie('user', response.data);
61
55
 
62
- console.log(response.data)
63
-
64
56
  Object.assign(state.user, {
65
57
  ...response.data
66
58
  });
@@ -76,7 +68,8 @@
76
68
 
77
69
  Object.assign(state.access, {
78
70
  token: null,
79
- status: false
71
+ status: false,
72
+ roles: null
80
73
  });
81
74
 
82
75
  setError(error)
@@ -0,0 +1,57 @@
1
+ const jwt = require('jsonwebtoken');
2
+ const fetch = require('node-fetch');
3
+ const jwkToPem = require('jwk-to-pem');
4
+
5
+ async function verifyAppleIdToken(id_token) {
6
+ // Decode the token (without verification)
7
+ const decodedToken = jwt.decode(id_token, { complete: true });
8
+ if (!decodedToken) {
9
+ throw new Error('Failed to decode token.');
10
+ }
11
+
12
+ // Check iss claim
13
+ if (decodedToken.payload.iss !== 'https://appleid.apple.com') {
14
+ throw new Error('Invalid issuer.');
15
+ }
16
+
17
+ // Check aud claim - Replace YOUR_APP_CLIENT_ID with your client ID
18
+ if (decodedToken.payload.aud !== process.env.APPLE_CLIENTID) {
19
+ throw new Error('Invalid audience.');
20
+ }
21
+
22
+ // Ensure the token has not expired
23
+ const currentTimestamp = Math.floor(Date.now() / 1000);
24
+ if (currentTimestamp > decodedToken.payload.exp) {
25
+ throw new Error('Token has expired.');
26
+ }
27
+
28
+ // Fetch Apple's public keys
29
+ const applePublicKeys = await fetch('https://appleid.apple.com/auth/keys')
30
+ .then(response => response.json())
31
+ .catch(err => {
32
+ throw new Error('Failed to fetch Apple public keys.');
33
+ });
34
+
35
+ const appleKey = applePublicKeys.keys.find(key => key.kid === decodedToken.header.kid);
36
+ if (!appleKey) {
37
+ throw new Error('Invalid token key ID.');
38
+ }
39
+
40
+ // Convert JWK to PEM
41
+ const pem = jwkToPem(appleKey);
42
+
43
+ // Verify the token's signature using the PEM
44
+ try {
45
+ jwt.verify(id_token, pem, {
46
+ algorithms: ['RS256'],
47
+ issuer: 'https://appleid.apple.com'
48
+ });
49
+ } catch (err) {
50
+ console.log(err);
51
+ throw new Error('Token signature verification failed.');
52
+ }
53
+
54
+ return decodedToken.payload; // or return the entire payload, depending on your needs
55
+ }
56
+
57
+ module.exports = { verifyAppleIdToken };
@@ -3,6 +3,14 @@
3
3
  class="for-transition w-100"
4
4
  >
5
5
  <div
6
+ v-if="users.state.current.status === 'removed'"
7
+ class="flex-center flex pd-medium radius-big bg-grey uppercase t-semi w-100 h-100"
8
+ >
9
+ Sorry, user has been removed.
10
+ </div>
11
+
12
+ <div
13
+ v-else
6
14
  _id="dash"
7
15
  class="pd-b-extra pd-thin w-100"
8
16
  >
@@ -41,13 +49,19 @@
41
49
  <h3
42
50
  class="mn-thin"
43
51
  >
44
- {{users.state.current.profile.name ? users.state.current.profile.name : 'Не указан' }}
52
+ {{users.state.current.profile.name ? users.state.current.profile.name : 'Not specified' }}
45
53
  </h3>
46
54
 
47
55
  <p
48
- class="mn-small t-main t-semi"
56
+ class="mn-thin t-main t-semi"
49
57
  >
50
- @{{ users.state.current.username ? users.state.current.username : 'Не указан' }}
58
+ @{{ users.state.current.username ? users.state.current.username : 'Not specified' }}
59
+ </p>
60
+
61
+ <p
62
+ class="mn-small p-medium"
63
+ >
64
+ {{ users.state.current.profile.description ? users.state.current.profile.description : 'Not specified' }}
51
65
  </p>
52
66
 
53
67
  <div class="mn-medium flex-center flex-nowrap flex">
@@ -75,7 +89,7 @@
75
89
  :isMember="users.state.current.isMember"
76
90
  :targetId="users.state.current._id"
77
91
  :userId="auth.state.user._id"
78
- class="w-min mn-auto"
92
+ class="w-min mn-medium mn-r-auto mn-l-auto"
79
93
  @updateMembership="handleMembershipUpdate"
80
94
  />
81
95
 
@@ -142,8 +156,8 @@
142
156
  <span
143
157
  class="t-red"
144
158
  >
145
- Logout
146
- </span>
159
+ Logout
160
+ </span>
147
161
  </MenuItem>
148
162
  </Menu>
149
163
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  <Field
14
14
  v-model:field="user.username"
15
- label="Username"
15
+ label="@"
16
16
  placeholder="Not specified"
17
17
  class="mn-thin w-100 bg-grey pd-medium radius-small"
18
18
  disabled="true"
@@ -88,8 +88,6 @@
88
88
  />
89
89
  <!-- -->
90
90
  <h3 class="mn-small">Account</h3>
91
-
92
- <p class="mn-thin">If you want to change your account details please contact the administratior: admin@thecommunephuket.com</p>
93
91
 
94
92
  <Field
95
93
  v-model:field="user.phone"
@@ -104,12 +102,14 @@
104
102
  v-model:field="user.email"
105
103
  label="Email"
106
104
  placeholder="Not specified"
107
- class="mn-thin bg-grey pd-medium radius-small"
105
+ class="mn-semi bg-grey pd-medium radius-small"
108
106
  :disabled="true"
109
107
  :validation="organizationName"
110
108
  />
111
109
 
112
- <Button :submit="onSubmit" :callback="redirectTo" class="mn-thin">Сохранить</Button>
110
+ <Button :submit="onSubmit" :callback="redirectTo" class="mn-thin">Save</Button>
111
+
112
+ <Button :submit="onSubmitDelete" :callback="a = () => {router.push({name: 'Sign In'})}" class="mn-thin bg-red t-white">Delete Account</Button>
113
113
  </div>
114
114
  </template>
115
115
 
@@ -141,7 +141,17 @@
141
141
  async function onSubmit() {
142
142
  await users.actions.update(users.state.current)
143
143
  }
144
+ async function onSubmitDelete() {
145
+ const confirmation = window.confirm("Are you sure you want to delete your account? Restoration will be possible only with the help of an administrator.");
146
+
147
+ if (!confirmation) {
148
+ return;
149
+ }
144
150
 
151
+ users.state.current.status = 'removed'
152
+ await users.actions.update(users.state.current)
153
+ auth.actions.logout()
154
+ }
145
155
  function redirectTo () {
146
156
  router.replace({ name: 'User Profile', params: { _id: users.state.current._id }});
147
157
  }
@@ -5,8 +5,16 @@ module.exports = (mongoose) => {
5
5
 
6
6
  phone: String,
7
7
  email: String,
8
+ apple_id: String,
8
9
  password: String,
9
-
10
+
11
+ status: {
12
+ type: String,
13
+ enum: ['active','banned','removed'],
14
+ default: 'active',
15
+ required: true,
16
+ },
17
+
10
18
  profile: {
11
19
  photo: {
12
20
  type: String,
@@ -13,6 +13,8 @@ const state = reactive({
13
13
  email: "",
14
14
  phone: "",
15
15
 
16
+ status: "",
17
+
16
18
  profile: {
17
19
  name: "",
18
20
  photo: "",
@@ -71,7 +73,6 @@ const actions = {
71
73
  },
72
74
 
73
75
  async update(user) {
74
- console.log(user)
75
76
  try {
76
77
  const response = await $axios.put(`/api/users/${user._id}`, user);
77
78
  mutations.set(response.data, 'current');