Compare commits

...

9 commits
v0.2 ... master

Author SHA1 Message Date
slynn1324
d645768dd0
Delete .github/workflows/codeql-analysis.yml 2025-01-27 19:26:19 -06:00
slynn1324
6dc5f188e0
Merge pull request #7 from slynn1324/dependabot/npm_and_yarn/multi-6bc014718a
Bump path-to-regexp and express
2025-01-27 19:25:19 -06:00
dependabot[bot]
8af7f57094
Bump path-to-regexp and express
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.12 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `path-to-regexp` from 0.1.7 to 0.1.12
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.7...v0.1.12)

Updates `express` from 4.17.1 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.1...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-28 01:19:24 +00:00
slynn1324
62a61aed72
Merge pull request #4 from ryanfiller/master
create firefox-extension, replace all chrome.func with browser.func
2025-01-27 10:35:56 -06:00
slynn1324
58c583d461
Merge pull request #3 from battlesloth/master
Add WebP support
2025-01-25 16:30:52 -06:00
ryanfiller
219f6d48b5 create firefox-extension, replace all chrome.func with browser.func 2024-05-16 13:07:00 -05:00
Jeff Rector
0cc19c48c0 Add WebP support 2023-02-01 07:38:20 -05:00
slynn1324
fed01f948b fix addpin 2021-10-04 20:17:12 -05:00
slynn1324
0bccaef904 let calls with x-api-key bypass csrf checking 2021-10-04 19:57:46 -05:00
17 changed files with 8882 additions and 369 deletions

View file

@ -1,71 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '40 2 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View file

@ -73,6 +73,23 @@ app.addSetter("hash.parse", (data) => {
});
app.addSetter("load.user", async (data) => {
store.do("loader.show");
let res = await fetch("/api/whoami");
if ( res.status == 200 ){
data.user = await res.json();
window.csrfToken = data.user.csrf;
} else {
console.log("error getting user");
}
store.do("loader.hide");
});
app.addSetter("load.boards", async (data) => {
store.do("loader.show");
@ -138,7 +155,7 @@ app.addSetter('addPinModal.save', async (data) => {
if ( boardId == "new" ){
let res = await fetch('api/boards', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
headers: { 'Content-Type': 'application/json', 'x-csrf-token': window.csrfToken },
body: JSON.stringify({
"name": data.addPinModal.newBoardName
})
@ -161,7 +178,8 @@ app.addSetter('addPinModal.save', async (data) => {
let res = await fetch('api/pins', {
method: 'POST',
headers: {
'Content-Type': "application/json"
'Content-Type': "application/json",
'x-csrf-token': window.csrfToken
},
body: JSON.stringify(postData)
});
@ -349,6 +367,8 @@ if ( target ){
store.do('hash.parse');
store.do("load.user");
store.do('load.boards');
Reef.databind(appComponent);

View file

@ -103,6 +103,8 @@ app.addSetter("app.uploadDroppedFiles", async (data, evt) => {
let boardId = store.data.board.id;
const supportedTypes = ["image/jpeg","image/png","image/webp"];
if ( boardId ){
let hasFiles = event.dataTransfer.types.find(i => i == "Files") == "Files";
if ( hasFiles ){
@ -115,9 +117,9 @@ app.addSetter("app.uploadDroppedFiles", async (data, evt) => {
if ( evt.dataTransfer.items[i].kind === "file" ){
let file = evt.dataTransfer.items[i].getAsFile();
if ( file.type != "image/jpeg" && file.type != "image/png" ){
if ( !supportedTypes.includes(file.type)){
window.alert("Unsupported file type. JPEG and PNG images are supported.");
window.alert("Unsupported file type. JPEG, PNG, and WebP images are supported.");
console.log("Unsupported file type: " + file.type);
return;

View file

@ -142,10 +142,12 @@ app.addSetter('addPinModal.fileChosen', (data, target) => {
let file = target.files[0];
const supportedTypes = ["image/jpeg","image/png","image/webp"];
// check type
if ( file.type != "image/jpeg" && file.type != "image/png" ){
if ( !supportedTypes.includes(file.type)){
window.alert("Unsupported file type. JPEG and PNG images are supported.");
window.alert("Unsupported file type. JPEG, PNG and WebP images are supported.");
console.log("Unsupported file type: " + file.type);
document.getElementById("fileInput").value = "";

View file

@ -0,0 +1,80 @@
/**
* Returns a handler which will open a new window when activated.
*/
function getClickHandler() {
return function(info, tab) {
if ( !info.srcUrl.startsWith('http') ){
window.alert("Image source is not a URL.");
return;
}
var w = 700;
var h = 800;
var left = (screen.width/2)-(w/2);
var top = (screen.height/2)-(h/2);
let s = "";
if ( info.linkUrl ){
s = info.linkUrl;
// strip the google images redirect
if ( s.startsWith("https://www.google.com/url?") ){
let parts = s.split("?");
if ( parts.length == 2 ){
let params = parts[1].split("&");
for( let i = 0; i < params.length; ++i ){
let kv = params[i].split("=");
if ( kv.length == 2 ){
if ( kv[0] == "url" ){
s = decodeURIComponent(kv[1]);
}
}
}
}
}
s = encodeURIComponent(s);
} else {
s = encodeURIComponent(info.pageUrl);
}
var q = "i=" + encodeURIComponent(info.srcUrl) + "&s=" + s;
browser.storage.sync.get({
server: 'http://localhost:3000'
}, function(items){
let server = items.server;
if ( !server.endsWith('/') ){
server += '/';
}
var url = server + 'addpin.html#' + q;
// Create a new window to the info page.
// browser.windows.create({ url: url, width: 520, height: 660 });
browser.windows.create({ url: url, width: w, height: h, left: left, top: top, type: 'popup' });
});
};
};
/**
* Create a context menu which will only show up for images.
*/
browser.contextMenus.create({
"title" : "add to tinypin",
"type" : "normal",
"contexts" : ["image"],
"onclick" : getClickHandler()
});

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

View file

@ -0,0 +1,36 @@
{
"name": "add to tinypin",
"version": "1.0.0",
"description": "add to tinypin context menu plugin",
"manifest_version": 2,
"background" : {
"scripts": ["background.js"],
"persistent": true
},
"options_ui" : {
"page": "options.html",
"open_in_tab": false
},
"permissions" : [
"contextMenus",
"storage"
],
"icons": {
"16" : "icon16.png",
"32" : "icon32.png",
"48" : "icon48.png",
"128" : "icon128.png"
},
"browser_action" :{
"default_title": "add to tinypin",
"default_icon" :{
"16": "icon16.png",
"32": "icon32.png"
}
},
"browser_specific_settings": {
"gecko": {
"id": "@slynn1324"
}
}
}

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>tinypin options</title>
<link rel="stylesheet" href="./bulma-custom.css" />
</head>
<body>
<div class="secton">
<div class="content" style="margin: 10px;">
<div class="field">
<label class="label">tinypin server url</label>
<div class="control">
<input class="input" id="server" type="text">
</div>
</div>
<button class="button is-success" id="save">Save</button>
<span id="status" style="line-height: 2.5em; color: #3273dc;"></span>
</div>
</div>
<script src="options.js"></script>
</body>
</html>

View file

@ -0,0 +1,25 @@
function restoreOptions(){
browser.storage.sync.get({
server: 'http://localhost:3000'
}, function(items){
document.getElementById('server').value = items.server;
});
}
function saveOptions(){
let server = document.getElementById('server').value;
browser.storage.sync.set({
server: server
}, function(){
let status = document.getElementById('status');
status.innerText = 'Options saved.';
setTimeout(function(){
status.innerText = '';
}, 1000);
});
}
document.addEventListener('DOMContentLoaded', restoreOptions);
document.getElementById('save').addEventListener('click', saveOptions);

1189
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@
"cookie-parser": "^1.4.5",
"csurf": "^1.11.0",
"eta": "^1.12.3",
"express": "^4.17.1",
"express": "^4.21.2",
"express-rate-limit": "^5.4.0",
"express-ws": "^5.0.2",
"multer": "^1.4.3",

View file

@ -108,45 +108,18 @@ module.exports = async () => {
app.set('json spaces', 2);
app.use(cookieParser());
// api method that are not subject to CSRF checks
// handle raw uploads for pin creation
app.post("/up", async (req, res) => {
try {
require("fs").writeFileSync("up.jpg", req.body);
// try to parse the image first... if this blows up we'll stop early
let image = await imageUtils.processImage(req.body);
let boardName = req.headers['board-name'].trim();
// get the board
let board = dao.findBoardByUserAndName(req.user.id, boardName);
if ( !board ){
board = dao.createBoard(req.user.id, boardName, 0);
}
let pin = dao.createPin(req.user.id, board.id, null, null, null, null, image.original.height, image.original.width, image.thumbnail.height, image.thumbnail.height);
await imageUtils.saveImage(req.user.id, pin.id, image);
broadcast(req.user.id, {updateBoard:board.id});
res.status(200).send(pin);
} catch (err){
console.log(`Error uploading pin`, err);
res.status(500).send(SERVER_ERROR);
// only appy csrf if we don't have an x-api-key header. The value of the x-api-key will be validated by the auth middleware
app.use( (req,res,next) => {
let apiKey = req.headers["x-api-key"];
if ( apiKey ){
next();
} else {
csrf({cookie:true})(req,res,next);
}
});
// all other endpoints require csrf
app.use(csrf({cookie:true}));
// // all other endpoints require csrf
// app.use(csrf({cookie:true}));
// accept websocket connections. currently are parsing the userid from the path to
// map the connections to only notify on changes from the same user.
@ -397,6 +370,37 @@ module.exports = async () => {
});
// api method that are not subject to CSRF checks
// handle raw uploads for pin creation
app.post("/up", async (req, res) => {
try {
require("fs").writeFileSync("up.jpg", req.body);
// try to parse the image first... if this blows up we'll stop early
let image = await imageUtils.processImage(req.body);
let boardName = req.headers['board-name'].trim();
// get the board
let board = dao.findBoardByUserAndName(req.user.id, boardName);
if ( !board ){
board = dao.createBoard(req.user.id, boardName, 0);
}
let pin = dao.createPin(req.user.id, board.id, null, null, null, null, image.original.height, image.original.width, image.thumbnail.height, image.thumbnail.height);
await imageUtils.saveImage(req.user.id, pin.id, image);
broadcast(req.user.id, {updateBoard:board.id});
res.status(200).send(pin);
} catch (err){
console.log(`Error uploading pin`, err);
res.status(500).send(SERVER_ERROR);
}
});
// handle multipart uploads for pin creation