コミット
f0286e87fc

+ 16
- 0
.editorconfig ファイルの表示

@@ -0,0 +1,16 @@
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[{package.json,*.yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false

+ 6
- 0
.env.example ファイルの表示

@@ -0,0 +1,6 @@
HOST=0.0.0.0
PORT=1337
APP_KEYS="toBeModified1,toBeModified2"
API_TOKEN_SALT=tobemodified
ADMIN_JWT_SECRET=tobemodified
JWT_SECRET=tobemodified

+ 3
- 0
.eslintignore ファイルの表示

@@ -0,0 +1,3 @@
.cache
build
**/node_modules/**

+ 27
- 0
.eslintrc ファイルの表示

@@ -0,0 +1,27 @@
{
"parser": "babel-eslint",
"extends": "eslint:recommended",
"env": {
"commonjs": true,
"es6": true,
"node": true,
"browser": false
},
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": false
},
"sourceType": "module"
},
"globals": {
"strapi": true
},
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"linebreak-style": ["error", "unix"],
"no-console": 0,
"quotes": ["error", "single"],
"semi": ["error", "always"]
}
}

+ 115
- 0
.gitignore ファイルの表示

@@ -0,0 +1,115 @@
############################
# OS X
############################

.DS_Store
.AppleDouble
.LSOverride
Icon
.Spotlight-V100
.Trashes
._*


############################
# Linux
############################

*~


############################
# Windows
############################

Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp


############################
# Packages
############################

*.7z
*.csv
*.dat
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
*.com
*.class
*.dll
*.exe
*.o
*.seed
*.so
*.swo
*.swp
*.swn
*.swm
*.out
*.pid


############################
# Logs and databases
############################

.tmp
*.log
*.sql
*.sqlite
*.sqlite3


############################
# Misc.
############################

*#
ssl
.idea
nbproject
public/uploads/*
!public/uploads/.gitkeep

############################
# Node.js
############################

lib-cov
lcov.info
pids
logs
results
node_modules
.node_history

############################
# Tests
############################

testApp
coverage

############################
# Strapi
############################

.env
license.txt
exports
*.cache
dist
build
.strapi-updater.json

+ 16
- 0
Dockerfile ファイルの表示

@@ -0,0 +1,16 @@
FROM node:16

WORKDIR ./src

COPY package*.json ./
COPY src ./

RUN npm install

ENV NODE_ENV='docker'

# Bundle app source
COPY . .

EXPOSE 3001
CMD [ "node", "server.js" ]

+ 57
- 0
README.md ファイルの表示

@@ -0,0 +1,57 @@
# 🚀 Getting started with Strapi

Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html) (CLI) which lets you scaffold and manage your project in seconds.

### `develop`

Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-develop)

```
npm run develop
# or
yarn develop
```

### `start`

Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-start)

```
npm run start
# or
yarn start
```

### `build`

Build your admin panel. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-build)

```
npm run build
# or
yarn build
```

## ⚙️ Deployment

Strapi gives you many possible deployment options for your project. Find the one that suits you on the [deployment section of the documentation](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/deployment.html).

## 📚 Learn more

- [Resource center](https://strapi.io/resource-center) - Strapi resource center.
- [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation.
- [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community.
- [Strapi blog](https://docs.strapi.io) - Official Strapi blog containing articles made by the Strapi team and the community.
- [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements.

Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome!

## ✨ Community

- [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team.
- [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members.
- [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi.

---

<sub>🤫 Psst! [Strapi is hiring](https://strapi.io/careers).</sub>

+ 8
- 0
config/admin.js ファイルの表示

@@ -0,0 +1,8 @@
module.exports = ({ env }) => ({
auth: {
secret: env('ADMIN_JWT_SECRET'),
},
apiToken: {
salt: env('API_TOKEN_SALT'),
},
});

+ 7
- 0
config/api.js ファイルの表示

@@ -0,0 +1,7 @@
module.exports = {
rest: {
defaultLimit: 25,
maxLimit: 100,
withCount: true,
},
};

+ 11
- 0
config/database.js ファイルの表示

@@ -0,0 +1,11 @@
const path = require('path');

module.exports = ({ env }) => ({
connection: {
client: 'sqlite',
connection: {
filename: path.join(__dirname, '..', env('DATABASE_FILENAME', '.tmp/data.db')),
},
useNullAsDefault: true,
},
});

+ 12
- 0
config/middlewares.js ファイルの表示

@@ -0,0 +1,12 @@
module.exports = [
'strapi::errors',
'strapi::security',
'strapi::cors',
'strapi::poweredBy',
'strapi::logger',
'strapi::query',
'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
];

+ 10
- 0
config/plugins.js ファイルの表示

@@ -0,0 +1,10 @@
module.exports = ({ env }) => ({
'users-permissions': {
enabled: true,
config: {
jwt: {
expiresIn: '15m',
},
},
},
});

+ 8
- 0
config/server.js ファイルの表示

@@ -0,0 +1,8 @@
module.exports = ({ env }) => ({
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
app: {
keys: env.array('APP_KEYS'),
},
url: 'http://localhost:1337'
});

+ 0
- 0
database/migrations/.gitkeep ファイルの表示


バイナリ
favicon.png ファイルの表示


+ 29464
- 0
package-lock.json
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 30
- 0
package.json ファイルの表示

@@ -0,0 +1,30 @@
{
"name": "diligent-rn-api",
"private": true,
"version": "0.1.0",
"description": "A Strapi application",
"scripts": {
"develop": "strapi develop",
"start": "strapi start",
"build": "strapi build",
"strapi": "strapi"
},
"dependencies": {
"@strapi/plugin-i18n": "4.5.3",
"@strapi/plugin-users-permissions": "4.5.3",
"@strapi/strapi": "4.5.3",
"better-sqlite3": "7.4.6",
"strapi-google-auth": "^0.1.2"
},
"author": {
"name": "A Strapi developer"
},
"strapi": {
"uuid": "e616c0a3-775a-4a60-9fd6-d7700ddc7e97"
},
"engines": {
"node": ">=14.19.1 <=18.x.x",
"npm": ">=6.0.0"
},
"license": "MIT"
}

+ 3
- 0
public/robots.txt ファイルの表示

@@ -0,0 +1,3 @@
# To prevent search engines from seeing the site altogether, uncomment the next two lines:
# User-Agent: *
# Disallow: /

+ 0
- 0
public/uploads/.gitkeep ファイルの表示


+ 39
- 0
src/admin/app.example.js ファイルの表示

@@ -0,0 +1,39 @@
const config = {
locales: [
// 'ar',
// 'fr',
// 'cs',
// 'de',
// 'dk',
// 'es',
// 'he',
// 'id',
// 'it',
// 'ja',
// 'ko',
// 'ms',
// 'nl',
// 'no',
// 'pl',
// 'pt-BR',
// 'pt',
// 'ru',
// 'sk',
// 'sv',
// 'th',
// 'tr',
// 'uk',
// 'vi',
// 'zh-Hans',
// 'zh',
],
};

const bootstrap = (app) => {
console.log(app);
};

export default {
config,
bootstrap,
};

+ 9
- 0
src/admin/webpack.config.example.js ファイルの表示

@@ -0,0 +1,9 @@
'use strict';

/* eslint-disable no-unused-vars */
module.exports = (config, webpack) => {
// Note: we provide webpack above so you should not `require` it
// Perform customizations to webpack config
// Important: return the modified config
return config;
};

+ 0
- 0
src/api/.gitkeep ファイルの表示


+ 33
- 0
src/api/post/content-types/post/schema.json ファイルの表示

@@ -0,0 +1,33 @@
{
"kind": "collectionType",
"collectionName": "posts",
"info": {
"singularName": "post",
"pluralName": "posts",
"displayName": "post"
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"title": {
"type": "string",
"required": true
},
"description": {
"type": "text",
"required": true
},
"profileImage": {
"allowedTypes": [
"images",
"files",
"videos",
"audios"
],
"type": "media",
"multiple": false
}
}
}

+ 9
- 0
src/api/post/controllers/post.js ファイルの表示

@@ -0,0 +1,9 @@
'use strict';

/**
* post controller
*/

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::post.post');

+ 9
- 0
src/api/post/routes/post.js ファイルの表示

@@ -0,0 +1,9 @@
'use strict';

/**
* post router
*/

const { createCoreRouter } = require('@strapi/strapi').factories;

module.exports = createCoreRouter('api::post.post');

+ 9
- 0
src/api/post/services/post.js ファイルの表示

@@ -0,0 +1,9 @@
'use strict';

/**
* post service
*/

const { createCoreService } = require('@strapi/strapi').factories;

module.exports = createCoreService('api::post.post');

+ 0
- 0
src/extensions/.gitkeep ファイルの表示


+ 72
- 0
src/extensions/users-permissions/content-types/user/schema.json ファイルの表示

@@ -0,0 +1,72 @@
{
"kind": "collectionType",
"collectionName": "up_users",
"info": {
"name": "user",
"description": "",
"singularName": "user",
"pluralName": "users",
"displayName": "User"
},
"options": {
"draftAndPublish": false,
"timestamps": true
},
"attributes": {
"username": {
"type": "string",
"minLength": 3,
"unique": true,
"configurable": false,
"required": true
},
"email": {
"type": "email",
"minLength": 6,
"configurable": false,
"required": true
},
"provider": {
"type": "string",
"configurable": false
},
"password": {
"type": "password",
"minLength": 6,
"configurable": false,
"private": true
},
"resetPasswordToken": {
"type": "string",
"configurable": false,
"private": true
},
"confirmationToken": {
"type": "string",
"configurable": false,
"private": true
},
"confirmed": {
"type": "boolean",
"default": false,
"configurable": false
},
"blocked": {
"type": "boolean",
"default": false,
"configurable": false
},
"role": {
"type": "relation",
"relation": "manyToOne",
"target": "plugin::users-permissions.role",
"inversedBy": "users",
"configurable": false
},
"country": {
"type": "string",
"maxLength": 2,
"minLength": 2
}
}
}

+ 38
- 0
src/extensions/users-permissions/controllers/validation/auth.js ファイルの表示

@@ -0,0 +1,38 @@
'use strict';

const { yup, validateYupSchema } = require('@strapi/utils');

const callbackBodySchema = yup.object().shape({
identifier: yup.string().required(),
password: yup.string().required(),
});

const registerBodySchema = yup.object().shape({
email: yup
.string()
.email()
.required(),
username: yup
.string()
.min(3)
.required(),
password: yup.string().required().matches(
/^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/,
"Password must be min 8 characters, and have 1 Special Character, 1 Uppercase, 1 Number and 1 Lowercase"
),
firstname: yup.string().required().min(3),
lastname: yup.string().required().min(3).max(30)
});

const sendEmailConfirmationBodySchema = yup.object().shape({
email: yup
.string()
.email()
.required(),
});

module.exports = {
validateCallbackBody: validateYupSchema(callbackBodySchema),
validateRegisterBody: validateYupSchema(registerBodySchema),
validateSendEmailConfirmationBody: validateYupSchema(sendEmailConfirmationBodySchema),
};

+ 301
- 0
src/extensions/users-permissions/strapi-server.js ファイルの表示

@@ -0,0 +1,301 @@
const utils = require("@strapi/utils");
const { getService } = require("../users-permissions/utils");
const jwt = require("jsonwebtoken");

const _ = require("lodash");

const {
validateCallbackBody,
validateRegisterBody,
validateSendEmailConfirmationBody,
} = require("../users-permissions/controllers/validation/auth");
const { setMaxListeners } = require("process");

const { sanitize } = utils;
const { ApplicationError, ValidationError } = utils.errors;

const emailRegExp =
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

const sanitizeUser = (user, ctx) => {
const { auth } = ctx.state;
const userSchema = strapi.getModel("plugin::users-permissions.user");

return sanitize.contentAPI.output(user, userSchema, { auth });
};

// issue a JWT
const issueJWT = (payload, jwtOptions = {}) => {
_.defaults(jwtOptions, strapi.config.get("plugin.users-permissions.jwt"));
return jwt.sign(
_.clone(payload.toJSON ? payload.toJSON() : payload),
strapi.config.get("plugin.users-permissions.jwtSecret"),
jwtOptions
);
};

// verify the refreshToken by using the REFRESH_SECRET from the .env
const verifyRefreshToken = (token) => {
return new Promise(function (resolve, reject) {
jwt.verify(
token,
process.env.REFRESH_SECRET,
{},
function (err, tokenPayload = {}) {
if (err) {
return reject(new Error("Invalid token."));
}
resolve(tokenPayload);
}
);
});
};

// issue a Refresh token
const issueRefeshToken = (payload, jwtOptions = {}) => {
_.defaults(jwtOptions, strapi.config.get("plugin.users-permissions.jwt"));
return jwt.sign(
_.clone(payload.toJSON ? payload.toJSON() : payload),
process.env.REFRESH_SECRET,
{ expiresIn: process.env.REFRESH_TOKEN_EXPIRES }
);
};

module.exports = (plugin) => {
// replace the following code line
// async callback(ctx) {

// with
plugin.controllers.auth.callback = async (ctx) => {
const provider = ctx.params.provider || "local";
const params = ctx.request.body;

const store = await strapi.store({
type: "plugin",
name: "users-permissions",
});
console.log("login");
if (provider === "local") {
if (!_.get(await store.get({ key: "grant" }), "email.enabled")) {
throw new ApplicationError("This provider is disabled");
}

await validateCallbackBody(params);

const query = { provider };

// Check if the provided identifier is an email or not.
const isEmail = emailRegExp.test(params.identifier);

// Set the identifier to the appropriate query field.
if (isEmail) {
query.email = params.identifier.toLowerCase();
} else {
query.username = params.identifier;
}

// Check if the user exists.
const user = await strapi
.query("plugin::users-permissions.user")
.findOne({ where: query });

if (!user) {
throw new ValidationError("Invalid identifier or password");
}

if (
_.get(await store.get({ key: "advanced" }), "email_confirmation") &&
user.confirmed !== true
) {
throw new ApplicationError("Your account email is not confirmed");
}

if (user.blocked === true) {
throw new ApplicationError(
"Your account has been blocked by an administrator"
);
}

// The user never authenticated with the `local` provider.
if (!user.password) {
throw new ApplicationError(
"This user never set a local password, please login with the provider used during account creation"
);
}

const validPassword = await getService("user").validatePassword(
params.password,
user.password
);

if (!validPassword) {
throw new ValidationError("Invalid identifier or password");
} else {
const refreshToken = issueRefeshToken({ id: user.id });
// ctx.cookies.set("refreshToken", refreshToken, {
// httpOnly: true,
// secure: process.env.NODE_ENV === "production" ? true : false,
// maxAge: 1000 * 60 * 60 * 24 * 14, // 14 Day Age
// domain:
// process.env.NODE_ENV === "development"
// ? "localhost"
// : process.env.PRODUCTION_URL,
// sameSite: "strict",
// });
ctx.send({
jwt: issueJWT(
{ id: user.id },
{ expiresIn: process.env.JWT_SECRET_EXPIRES }
),
refreshToken: refreshToken,
user: await sanitizeUser(user, ctx),
});
}
} else {
try {
const user = await getService("providers").connect(provider, ctx.query);
const refreshToken = issueRefeshToken({ id: user.id });
// ctx.cookies.set("refreshToken", refreshToken, {
// httpOnly: true,
// secure: process.env.NODE_ENV === "production" ? true : false,
// maxAge: 1000 * 60 * 60 * 24 * 14, // 14 Day Age
// domain:
// process.env.NODE_ENV === "development"
// ? "localhost"
// : process.env.PRODUCTION_URL,
// sameSite: "strict",
// });
return ctx.send({
jwt: getService("jwt").issue(
{ id: user.id },
{ expiresIn: process.env.JWT_SECRET_EXPIRES }
),
refreshToken: refreshToken,
user: await sanitizeUser(user, ctx),
});
} catch (error) {
throw new ApplicationError(error.message);
}
}
};

/**
* Creating a new token based on the refreshCookie
*
*
* @param {*} ctx
* @returns
*/
plugin.controllers.auth["refreshToken"] = async (ctx) => {
// get token from the POST request
const store = await strapi.store({
type: "plugin",
name: "users-permissions",
});

// either as Cookie or in the body as refreshToken
const { refreshToken } = ctx.request.body;

//const refreshCookie = ctx.cookies.get("refreshToken");

if (!refreshToken) {
return ctx.badRequest("no Authorization");
}
// if (!refreshCookie) {
// if (refreshToken) {
// // in case we get the token in the body
// refreshCookie = refreshToken;
// } else {
// return ctx.badRequest("no Authorization");
// }
// }

try {
//const obj = await verifyRefreshToken(refreshCookie);
const obj = await verifyRefreshToken(refreshToken);
console.log(obj);
// Check if the user exists.
const user = await strapi
.query("plugin::users-permissions.user")
.findOne({ where: { id: obj.id } });
console.log(user);
if (!user) {
throw new ValidationError("Invalid identifier or password");
}

if (
_.get(await store.get({ key: "advanced" }), "email_confirmation") &&
user.confirmed !== true
) {
throw new ApplicationError("Your account email is not confirmed");
}

if (user.blocked === true) {
throw new ApplicationError(
"Your account has been blocked by an administrator"
);
}
const refreshJwtToken = issueRefeshToken({ id: user.id });
// ctx.cookies.set("refreshToken", refreshJwtToken, {
// httpOnly: true,
// secure: process.env.NODE_ENV === "production" ? true : false,
// maxAge: 1000 * 60 * 60 * 24 * 14, // 14 Day Age
// domain:
// process.env.NODE_ENV === "development"
// ? "localhost"
// : process.env.PRODUCTION_URL,
// sameSite: "strict",
// });
ctx.send({
jwt: issueJWT(
{ id: obj.id },
{ expiresIn: process.env.JWT_SECRET_EXPIRES }
),
refreshToken: refreshJwtToken,
});
} catch (err) {
return ctx.badRequest(err.toString());
}
};

plugin.controllers.auth["logout"] = async (ctx) => {
console.log("logout");
// delete the refresh cookie
ctx.cookies.set("refreshToken", "", {
httpOnly: true,
secure: process.env.NODE_ENV === "production" ? true : false,
maxAge: 1000 * 60 * 60 * 24 * 14, // 14 Day Age
domain:
process.env.NODE_ENV === "development"
? "localhost"
: process.env.PRODUCTION_URL,
sameSite: "strict",
});
ctx.send({
message: "ok",
});
};

plugin.routes["content-api"].routes.push({
method: "POST",
path: "/token/refresh",
handler: "auth.refreshToken",
config: {
policies: [],
prefix: "",
auth: false,
},
});

plugin.routes["content-api"].routes.push({
method: "GET",
path: "/auth/logout",
handler: "auth.logout",
config: {
policies: [],
prefix: "",
},
});

return plugin;
};

+ 10
- 0
src/extensions/users-permissions/utils/index.js ファイルの表示

@@ -0,0 +1,10 @@
"use strict";

const getService = (name) => {
return strapi.plugin("users-permissions").service(name);
return;
};

module.exports = {
getService,
};

+ 20
- 0
src/index.js ファイルの表示

@@ -0,0 +1,20 @@
'use strict';

module.exports = {
/**
* An asynchronous register function that runs before
* your application is initialized.
*
* This gives you an opportunity to extend code.
*/
register(/*{ strapi }*/) {},

/**
* An asynchronous bootstrap function that runs before
* your application gets started.
*
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
bootstrap(/*{ strapi }*/) {},
};

+ 10354
- 0
yarn.lock
ファイル差分が大きすぎるため省略します
ファイルの表示


読み込み中…
キャンセル
保存