Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TW-1459 Implement a minimal demo of categorizing web sites with Cyren API #164

Draft
wants to merge 5 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ THREE_ROUTE_API_AUTH_TOKEN=
REDIS_URL=
ADMIN_USERNAME=
ADMIN_PASSWORD=
CTWSD_CONTAINER_ADDRESS=
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:14
FROM node:20
WORKDIR /usr/src/app
COPY package.json yarn.lock ./
RUN yarn
Expand Down
12 changes: 12 additions & 0 deletions Dockerfile.ctwsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM --platform=linux/amd64 ubuntu:22.04
WORKDIR /usr/src/app
ARG CTWSD_FTP_URL
ARG CTWSD_FTP_USER
ARG CTWSD_FTP_PASS
ARG CTWSD_SERVER_ADDRESS
ARG CTWSD_LICENSE_KEY
COPY ./setup_ctwsd.sh ./ctwsd-config/* /usr/src/app/
RUN CTWSD_FTP_URL=${CTWSD_FTP_URL} CTWSD_FTP_USER=${CTWSD_FTP_USER} CTWSD_FTP_PASS=${CTWSD_FTP_PASS} \
CTWSD_LICENSE_KEY=${CTWSD_LICENSE_KEY} CTWSD_SERVER_ADDRESS=${CTWSD_SERVER_ADDRESS} ./setup_ctwsd.sh
EXPOSE 8080
CMD [ "./ctwsd/bin/ctwsd", "-i", "-c", "./ctwsd/bin/ctwsd.conf" ]
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ Use `yarn run build` for building.

## Building and running using Docker

Follow the instructions on [Building your image](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/#building-your-image) and [Running the image](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/#run-the-image). Change the port number in both `.env` and `Dockerfile` if the webapp should be run on another port than 3000.
Follow the instructions on [Building your image](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/#building-your-image) and [Running the image](https://nodejs.org/en/docs/guides/nodejs-docker-webapp/#run-the-image). Change the port number in both `.env` and `Dockerfile` if the webapp should be run on another port than 3000. You also need to build and run a container with `ctwsd`, see "Building and running `ctwsd` host".

## Running with pm2

You can run the built backend using `pm2 restart templewallet-backend.json`.
You can run the built backend using `pm2 restart templewallet-backend.json`. You also need to build and run a container with `ctwsd`, see "Building and running `ctwsd` host".

## Upstreaming using nginx

Expand Down Expand Up @@ -67,3 +67,19 @@ location /api/exchange-rates/ {
```

Replace 3000 with the respective port number if the backend is listening on a different one. Restart nginx using `sudo systemctl restart nginx` after changes are saved.

## Building and running `ctwsd` host

1. Build the image with command
```
docker build \
--build-arg CTWSD_FTP_URL=<URL to ctwsd archive for Ubuntu 22.04> \
--build-arg CTWSD_FTP_USER=<FTP server username> \
--build-arg CTWSD_FTP_PASS=<FTP server password> \
--build-arg CTWSD_SERVER_ADDRESS=<Cyren Datacenter server address> \
--build-arg CTWSD_LICENSE_KEY=<URLF License Key>:<OEM id> \
--file Dockerfile.ctwsd .
```
OEM id is an arbitrary alphanumeric string with up to 35 characters.
2. Get image ID with command `docker image ls`
3. Start a container with the new image using command `docker container run -d -p <destination port>:8080 <image ID>`
3 changes: 3 additions & 0 deletions ctwsd-config/CustomCategoryDefinition.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[501]
Name = Crypto
Description = Cryptocurrencies, blockchain, and so on
2 changes: 2 additions & 0 deletions ctwsd-config/CustomCategoryIndex.idx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/usr/src/app/cc_snapshot_1.txt
/usr/src/app/cc_delta_1
Empty file added ctwsd-config/cc_delta_1
Empty file.
37 changes: 37 additions & 0 deletions ctwsd-config/cc_snapshot_1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
ieh ether|bsc|blockchain|bitcoin|btc|^(www\.)?dex|litecoin|ripple|crypto|solana|altcoin|stablecoin|arbitrum|xtz|dapp|airdrop 501
i autofaucet.dutchycorp.space 501
i basescan.org 501
i bitdegree.org 501
i blockchair.com 501
i blockworks.co 501
i coin360.com 501
i coinarbitragebot.com 501
i coincarp.com 501
i coincheckup.com 501
i coincodex.com 501
i coincost.net 501
i coinedition.com 501
i coingape.com 501
i coingolive.com 501
i coinlisting.info 501
i coinmarketcap.com 501
i coinpaprika.com 501
i coinpedia.org 501
i coinspeaker.com 501
i cointelegraph.com 501
i cryptfaucet.com 501
i decrypt.co 501
i earn-pepe.com 501
i eth-converter.com 501
i nft.news 501
i polygonscan.com 501
i rollercoin.com 501
i solscan.io 501
i theblock.co 501
i thecoinrise.com 501
i tzkt.io 501
i u.today 501
i walletinvestor.com 501
i www.coindesk.com 501
i www.coingecko.com 501
i www.geckoterminal.com 501
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"pino-http": "^5.5.0",
"pino-pretty": "^4.7.1",
"qs": "^6.10.3",
"rate-limiter-flexible": "^5.0.3",
"semaphore": "^1.1.0",
"semver": "^7.6.0",
"swagger-jsdoc": "^6.2.8",
Expand Down
21 changes: 21 additions & 0 deletions setup_ctwsd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

CC_CONFDIR=/usr/src/app
ESCAPED_CC_CONFDIR=$(echo $CC_CONFDIR | sed 's/\//\\\//g')
DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y wget
wget $CTWSD_FTP_URL --user=$CTWSD_FTP_USER --password=$CTWSD_FTP_PASS --no-check-certificate -O ./ctwsd.tar.gz
tar -xzf ctwsd.tar.gz
rm ctwsd.tar.gz
mv ./ctwsd* ./ctwsd

CONF_FILE_PATH=./ctwsd/bin/ctwsd.conf
CC_CACHE_MAX_ENTRIES=10000
sed -i "s/ServerAddress \= xxxxxxxxx/ServerAddress = ${CTWSD_SERVER_ADDRESS}/" $CONF_FILE_PATH
sed -i "s/LicenseKey \= xxxxxxxxx/LicenseKey = ${CTWSD_LICENSE_KEY}/" $CONF_FILE_PATH
sed -i "s/#LocalCustomCategories-Enabled=0/LocalCustomCategories-Enabled=1/" $CONF_FILE_PATH
sed -i "s/#CustomCategoriesCacheMaxEntries=10000/CustomCategoriesCacheMaxEntries=${CC_CACHE_MAX_ENTRIES}/" \
$CONF_FILE_PATH
sed -i "s/#LocalCustomCategories-Uri=/LocalCustomCategories-Uri=${ESCAPED_CC_CONFDIR}\/CustomCategoryIndex.idx/" \
$CONF_FILE_PATH
sed -i "s/#LocalCustomCategoriesDefinitionFileURI=/LocalCustomCategoriesDefinitionFileURI=\
${ESCAPED_CC_CONFDIR}\/CustomCategoryDefinition.ini/" $CONF_FILE_PATH
3 changes: 2 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export const EnvVars = {
REDIS_URL: getEnv('REDIS_URL'),
ADMIN_USERNAME: getEnv('ADMIN_USERNAME'),
ADMIN_PASSWORD: getEnv('ADMIN_PASSWORD'),
COVALENT_API_KEY: getEnv('COVALENT_API_KEY')
COVALENT_API_KEY: getEnv('COVALENT_API_KEY'),
CTWSD_CONTAINER_ADDRESS: getEnv('CTWSD_CONTAINER_ADDRESS')
};

for (const name in EnvVars) {
Expand Down
15 changes: 15 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@
import { getAliceBobOrderInfo } from './utils/alice-bob/get-alice-bob-order-info';
import { getAliceBobPairInfo } from './utils/alice-bob/get-alice-bob-pair-info';
import { getAliceBobPairsInfo } from './utils/alice-bob/get-alice-bob-pairs-info';
import { getSiteCategories } from './utils/cyren-api';
import { CodedError } from './utils/errors';
import { withCodedExceptionHandler, withQueryParamsValidation } from './utils/express-helpers';
import { coinGeckoTokens } from './utils/gecko-tokens';
import { getExternalApiErrorPayload, isDefined, isNonEmptyString } from './utils/helpers';
import logger from './utils/logger';
import { getSignedMoonPayUrl } from './utils/moonpay/get-signed-moonpay-url';
import { adCategoryQueryParamsSchema } from './utils/schemas';
import { getSigningNonce } from './utils/signing-nonce';
import SingleQueryDataProvider from './utils/SingleQueryDataProvider';
import { tezExchangeRateProvider } from './utils/tezos';
Expand Down Expand Up @@ -66,6 +69,7 @@
app.use(pinoHttp(PINO_LOGGER));
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

const androidApp = firebaseAdmin.initializeApp(
{
Expand Down Expand Up @@ -156,7 +160,7 @@
await redisClient.lpush('notifications', JSON.stringify(newNotification));

res.status(200).send({ message: 'Notification added successfully', notification: newNotification });
} catch (error: any) {

Check warning on line 163 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
res.status(500).send({ error: error.message });
}
});
Expand Down Expand Up @@ -335,6 +339,17 @@

app.use('/api/slise-ad-rules', adRulesRouter);

app.get(
'/api/get-ad-category',
withCodedExceptionHandler(
withQueryParamsValidation(adCategoryQueryParamsSchema, async (req, res) => {
const categories = await getSiteCategories(req.query.url);

res.status(200).send(categories);
})
)
);

app.use('/api/evm', evmRouter);

app.post('/api/magic-square-quest/start', async (req, res) => {
Expand All @@ -342,7 +357,7 @@
await startMagicSquareQuest(req.body);

res.status(200).send({ message: 'Quest successfully started' });
} catch (error: any) {

Check warning on line 360 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
console.error(error);

if (error instanceof CodedError) {
Expand All @@ -356,7 +371,7 @@
app.get('/api/magic-square-quest/participants', basicAuth, async (req, res) => {
try {
res.status(200).send(await getMagicSquareQuestParticipants());
} catch (error: any) {

Check warning on line 374 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
console.error(error);

if (error instanceof CodedError) {
Expand All @@ -370,10 +385,10 @@
app.get('/api/signing-nonce', (req, res) => {
try {
const pkh = req.query.pkh;
if (!pkh || typeof pkh !== 'string') throw new Error('PKH is not a string');

Check warning on line 388 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected value in conditional. A boolean expression is required

res.status(200).send(getSigningNonce(pkh));
} catch (error: any) {

Check warning on line 391 in src/index.ts

View workflow job for this annotation

GitHub Actions / Checks if ts and lint works

Unexpected any. Specify a different type
console.error(error);

if (error instanceof CodedError) {
Expand Down
4 changes: 2 additions & 2 deletions src/utils/MutexProtectedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export default class MutexProtectedData<T> {
this.mutex = new PromisifiedSemaphore();
}

exec(task: () => void | Promise<void>) {
return this.mutex.exec(task);
exec<U = void>(task: (data: T, setData: (value: T) => void) => U | Promise<U>) {
return this.mutex.exec(() => task(this.data, value => void (this.data = value)));
}

setData(newData: T) {
Expand Down
8 changes: 4 additions & 4 deletions src/utils/PromisifiedSemaphore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ export default class PromisifiedSemaphore {
return this.semaphore.available(n);
}

exec(task: () => void | Promise<void>, n = 1) {
return new Promise<void>((resolve, reject) => {
exec<T>(task: () => T | Promise<T>, n = 1) {
return new Promise<T>((resolve, reject) => {
this.semaphore.take(n, async () => {
try {
await task();
resolve();
const value = await task();
resolve(value);
} catch (e) {
reject(e);
} finally {
Expand Down
4 changes: 3 additions & 1 deletion src/utils/SingleQueryDataProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ export default class SingleQueryDataProvider<T> {
) {
this.fetchMutex = new PromisifiedSemaphore();
this.readyMutex = new PromisifiedSemaphore();
this.state = new MutexProtectedData({ error: new Error('This error should not be displayed') });
this.state = new MutexProtectedData<SingleQueryDataProviderState<T>>({
error: new Error('This error should not be displayed')
});
this.init();
}

Expand Down
Loading
Loading