Skip to content
This repository has been archived by the owner on Feb 25, 2024. It is now read-only.

Commit

Permalink
Add rate limiting
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldev5 committed Aug 8, 2023
1 parent 066f6c5 commit 72c0b86
Show file tree
Hide file tree
Showing 17 changed files with 668 additions and 8 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
RATE_LIMIT_TTL_SEC=60
RATE_LIMIT_REQ_COUNT_PUBLIC=20
RATE_LIMIT_REQ_COUNT_AUTH=100
JWT_SECRET_KEY=
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = {
node: true,
jest: true,
},
ignorePatterns: ['.eslintrc.js'],
ignorePatterns: ['.eslintrc.js', 'client/**'],
rules: {
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ lerna-debug.log*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/extensions.json

.env
57 changes: 57 additions & 0 deletions client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html>
<head>
<title>Lightspell ⚡️</title>
<link rel="stylesheet" href="style.css" />
<link
href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;600&display=swap"
rel="stylesheet"
/>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script src="script.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div class="container">
<div class="header-container">
<img src="logo.png" alt="Lightspell Logo" class="header-logo" />
<p class="header-slogan">
Your gateway to enhanced cross-chain experiences!
</p>
</div>

<div class="section">
<h2 class="section-title">Generate Your API Key</h2>
<p class="section-content">
Unlock the full potential of XCM-API by generating your own API key.
With an API key, you can access the enhanced features and higher
request limits. Start building cross-chain applications seamlessly!
</p>
<div class="subsection">
<h3 class="subsection-title">Requests Limitations</h3>
<p class="subsection-content">
Without an API key, you have a limit of 20 requests per minute. Once
you generate an API key, your limit increases to 100 requests per
minute, allowing you to build and scale your applications
effectively.
</p>
</div>
<form
class="api-form"
action=""
method="GET"
onsubmit="submitForm(event)"
>
<div
class="g-recaptcha"
data-sitekey="6LfL0oYnAAAAAEwDq-0SBKDRF1WyIK5H8LV8eHcI"
></div>
<p id="captcha-message">Please complete the reCAPTCHA.</p>
<!-- <label for="username">Username:</label>
<input type="text" id="username" name="username" required /> -->
<button type="submit">Generate API Key</button>
</form>
</div>
</div>
</body>
</html>
Binary file added client/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions client/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
function submitForm(event) {
event.preventDefault();

var response = grecaptcha.getResponse();
var captchaMessage = document.getElementById('captcha-message');

if (response.length === 0) {
captchaMessage.style.display = 'block';
} else {
fetch('/auth/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ recaptchaResponse: response }),
})
.then((response) => {
if (!response.ok) {
if (response.status === 403) {
captchaMessage.textContent =
'Captcha verification failed. Please try again.';
} else if (response.status === 500) {
captchaMessage.textContent =
'Error verifying captcha on the server. Please try again later.';
} else {
captchaMessage.textContent =
'An error occurred during API request. Please try again.';
}
captchaMessage.style.display = 'block';
throw new Error('API request failed');
}
return response.json();
})
.then((data) => {
if (data.api_key) {
sessionStorage.setItem('api_key', data.api_key);
window.location.href = 'show-api-key.html';
} else {
console.error('API key not received in the response.');
}
})
.catch((error) => {
console.error('Error during API request:', error);
});
}
}
81 changes: 81 additions & 0 deletions client/show-api-key.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html>
<head>
<title>API Key</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
color: #333;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
max-width: 400px;
text-align: center;
background-color: #fff;
padding: 20px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
border-radius: 8px;
}
h2 {
margin-bottom: 10px;
}
p {
margin-bottom: 20px;
}
#api-key {
display: block;
background-color: #f9f9f9;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 20px;
word-break: break-all;
}
#copy-button {
background-color: #007bff;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div class="container">
<h2>Your Generated API Key</h2>
<p>Copy and save this API key for future use:</p>
<div id="api-key"></div>
<button id="copy-button">Copy</button>
</div>
<script>
var apiKey = sessionStorage.getItem('api_key');
if (apiKey) {
var apiKeyDisplay = document.getElementById('api-key');
apiKeyDisplay.textContent = apiKey;

var copyButton = document.getElementById('copy-button');
copyButton.addEventListener('click', function () {
// Copy the API key to the clipboard
var textArea = document.createElement('textarea');
textArea.value = apiKey;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);

copyButton.textContent = 'Copied!';
});
} else {
console.error('API key not found in session.');
}
</script>
</body>
</html>
111 changes: 111 additions & 0 deletions client/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
body {
font-family: 'Open Sans', sans-serif;
font-size: 16px;
line-height: 1.6;
margin: 0;
padding: 0;
color: #333;
background-color: #f4f4f4;
}

.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.header {
text-align: center;
margin-bottom: 20px;
}

.section {
margin-bottom: 30px;
}

.section-title {
font-size: 24px;
margin-bottom: 10px;
}

.section-content {
font-size: 16px;
}

.logo {
max-width: 250px;
margin: 0 auto;
display: block;
}

.api-form {
background-color: #f9f9f9;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.api-form label {
display: block;
margin-bottom: 8px;
font-weight: bold;
}

.api-form input[type='text'],
.api-form input[type='email'] {
width: 100%;
padding: 10px;
margin-bottom: 20px;
border: 1px solid #ccc;
border-radius: 4px;
}

.api-form button[type='submit'] {
background-color: #007bff;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 10px;
}

.header-container {
color: #333;
padding: 20px 0;
text-align: center;
}
.header-logo {
max-width: 200px;
display: block;
margin: 0 auto;
}
.header-slogan {
font-size: 18px;
margin-top: 10px;
}

#captcha-message {
display: none;
color: red;
font-size: 14px;
margin: 0;
margin-top: 8px;
margin-bottom: 8px;
}

@media only screen and (max-width: 500px) {
.g-recaptcha {
transform: scale(0.77);
transform-origin: 0 0;
}
}

@media only screen and (max-width: 300px) {
.g-recaptcha {
transform: scale(0.66);
transform-origin: 0 0;
}
}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,19 @@
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.0.0",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.1.0",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/serve-static": "^4.0.0",
"@nestjs/throttler": "4.2.0",
"@paraspell/sdk": "^2.0.5",
"@polkadot/api": "^10.9.1",
"@polkadot/api-base": "^10.9.1",
"@polkadot/apps-config": "^0.124.1",
"@polkadot/types": "^10.9.1",
"axios": "^1.4.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"reflect-metadata": "^0.1.13",
Expand Down
Loading

0 comments on commit 72c0b86

Please sign in to comment.