Compare commits

...

26 Commits

Author SHA1 Message Date
22015044a5 10.22.0 2018-10-17 04:17:19 +09:00
61f86dcb2b Resolve #2923
Allow option to disable sending HSTS headers even if https:// is used in url
2018-10-17 04:15:41 +09:00
8f3bce6b11 Add some messaging API tests 2018-10-17 04:01:13 +09:00
ee736e73a9 Merge pull request #2922 from syuilo/greenkeeper/reconnecting-websocket-4.1.9
Update reconnecting-websocket to the latest version 🚀
2018-10-17 03:54:08 +09:00
99f867897e fix(package): update reconnecting-websocket to version 4.1.9 2018-10-16 18:53:19 +00:00
c66c5b6e75 Fix bug 2018-10-17 03:47:32 +09:00
f25ecc19b9 🎨 2018-10-17 03:41:55 +09:00
48e09970f3 Merge pull request #2921 from syuilo/l10n_develop
New Crowdin translations
2018-10-16 22:46:43 +09:00
f05cb79604 10.21.3 2018-10-16 22:26:43 +09:00
46d3293edd Fix #2920 2018-10-16 22:21:08 +09:00
9703d613cf 10.21.2 2018-10-16 20:59:49 +09:00
704e217dbb オブジェクトストレージのURLに拡張子を含めるように 2018-10-16 20:59:36 +09:00
a103032d94 10.21.1 2018-10-16 20:34:32 +09:00
c7207a4bd7 Fix #2919 2018-10-16 20:33:13 +09:00
35c65fe589 Clean up 2018-10-16 20:29:35 +09:00
6d5bd0c484 10.21.0 2018-10-16 20:19:55 +09:00
cfbb6e8092 オブジェクトストレージのURLにファイル名を含めるのを廃止 2018-10-16 20:14:06 +09:00
feef4a933e Update src/tools/clean-remote-files.ts 2018-10-16 20:10:46 +09:00
468bc67569 Improve test 2018-10-16 19:52:14 +09:00
0d517fa52f Greenkeeper/monorepo.fortawesome 5.4.1 (#2917)
* fix(package): update @fortawesome/fontawesome-svg-core to version 1.2.6

Closes #2861

* fix(package): update @fortawesome/free-regular-svg-icons to version 5.4.1

Closes #2861

* fix(package): update @fortawesome/free-solid-svg-icons to version 5.4.1

Closes #2861
2018-10-16 12:28:45 +09:00
d9054367c1 fix(package): update @fortawesome/free-brands-svg-icons to version 5.4.1 (#2916)
Closes #2859
2018-10-16 12:27:03 +09:00
1213373027 Use cache with RSS (#2915) 2018-10-16 12:24:54 +09:00
100a525507 Update autogen.sh (#2914)
refs: 8b98c08a81 (commitcomment-30911933)
2018-10-16 11:45:11 +09:00
92ba64c35c New translations ja-JP.yml (German) 2018-10-16 06:11:24 +09:00
a8ee51ffd6 New translations ja-JP.yml (German) 2018-10-16 05:51:14 +09:00
5538afc61d New translations ja-JP.yml (German) 2018-10-16 05:42:36 +09:00
13 changed files with 164 additions and 44 deletions

View File

@ -30,7 +30,7 @@ while :
touch patreon.cache && \
rm patreon.cache && \
cat patreon.raw.cache | \
jq -r '(.data|map(select(.relationships.currently_entitled_tiers.data[]))|map(.relationships.user.data.id))as$data|.included|map(select(.attributes.hide_pledges==false))|map(select(.id as$id|$data|contains([$id])))|map(.attributes|[.full_name,.thumb_url,.url]|@tsv)|.[]|@text' >> patreon.cache && \
jq -r '(.data|map(select(.relationships.currently_entitled_tiers.data[]))|map(.relationships.user.data.id))as$data|.included|map(select(.id as$id|$data|contains([$id])))|map(.attributes|[.full_name,.thumb_url,.url]|@tsv)|.[]|@text' >> patreon.cache && \
echo '<table><tr>' >> patreon.md.cache && \
cat patreon.cache | \
awk -F'\t' '{print $2,$1}' | \

View File

@ -1,8 +1,8 @@
{
"name": "misskey",
"author": "syuilo <i@syuilo.com>",
"version": "10.20.0",
"clientVersion": "1.0.10607",
"version": "10.22.0",
"clientVersion": "1.0.10633",
"codename": "nighthike",
"main": "./built/index.js",
"private": true,
@ -20,10 +20,10 @@
"format": "gulp format"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "1.2.4",
"@fortawesome/free-brands-svg-icons": "5.3.1",
"@fortawesome/free-regular-svg-icons": "5.3.1",
"@fortawesome/free-solid-svg-icons": "5.3.1",
"@fortawesome/fontawesome-svg-core": "1.2.6",
"@fortawesome/free-brands-svg-icons": "5.4.1",
"@fortawesome/free-regular-svg-icons": "5.4.1",
"@fortawesome/free-solid-svg-icons": "5.4.1",
"@koa/cors": "2.2.2",
"@prezzemolo/rap": "0.1.2",
"@prezzemolo/zip": "0.0.3",
@ -179,7 +179,7 @@
"qrcode": "1.3.0",
"ratelimiter": "3.2.0",
"recaptcha-promise": "0.1.3",
"reconnecting-websocket": "4.1.8",
"reconnecting-websocket": "4.1.9",
"redis": "2.8.0",
"request": "2.88.0",
"request-promise-native": "1.0.5",

View File

@ -44,7 +44,6 @@ export default define({
},
fetch() {
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${this.props.url}`, {
cache: 'no-cache'
}).then(res => {
res.json().then(feed => {
this.items = feed.items;

View File

@ -307,7 +307,7 @@ export default Vue.extend({
display block
width 100%
padding 16px
color #555
color var(--text)
border-top solid 1px rgba(#000, 0.05)
&:hover
@ -326,6 +326,6 @@ export default Vue.extend({
margin 0
padding 16px
text-align center
color #aaa
color var(--text)
</style>

View File

@ -2,8 +2,8 @@
<div class="mk-ui" v-hotkey.global="keymap">
<div class="bg" v-if="$store.getters.isSignedIn && $store.state.i.wallpaperUrl" :style="style"></div>
<x-header class="header" v-if="navbar == 'top'" v-show="!zenMode" ref="header"/>
<x-sidebar class="sidebar" v-if="navbar != 'top'" ref="sidebar"/>
<div class="content" :class="[{ sidebar: navbar != 'top' }, navbar]">
<x-sidebar class="sidebar" v-if="navbar != 'top'" v-show="!zenMode" ref="sidebar"/>
<div class="content" :class="[{ sidebar: navbar != 'top', zen: zenMode }, navbar]">
<slot></slot>
</div>
<mk-stream-indicator v-if="$store.getters.isSignedIn"/>
@ -73,7 +73,9 @@ export default Vue.extend({
toggleZenMode() {
this.zenMode = !this.zenMode;
this.$nextTick(() => {
this.$store.commit('setUiHeaderHeight', this.$refs.header.$el.offsetHeight);
if (this.$refs.header) {
this.$store.commit('setUiHeaderHeight', this.$refs.header.$el.offsetHeight);
}
});
}
}
@ -102,4 +104,7 @@ export default Vue.extend({
> .content.sidebar.right
padding-right 68px
> .content.zen
padding 0 !important
</style>

View File

@ -1,5 +1,5 @@
<template>
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/>
<x-notes ref="timeline" :more="existMore ? more : null" :media-view="mediaView"/>
</template>
<script lang="ts">

View File

@ -15,7 +15,7 @@
<ui-switch v-model="column.isMediaView" @change="onChangeSettings">%i18n:@is-media-view%</ui-switch>
</div>
<x-list-tl v-if="column.type == 'list'" :list="column.list" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/>
<x-hashtag-tl v-if="column.type == 'hashtag'" :tag-tl="$store.state.settings.tagTimelines.find(x => x.id == column.tagTlId)" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/>
<x-hashtag-tl v-else-if="column.type == 'hashtag'" :tag-tl="$store.state.settings.tagTimelines.find(x => x.id == column.tagTlId)" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/>
<x-tl v-else :src="column.type" :media-only="column.isMediaOnly" :media-view="column.isMediaView"/>
</x-column>
</template>

View File

@ -23,6 +23,7 @@ export type Source = {
url: string;
port: number;
https?: { [x: string]: string };
disableHsts?: boolean;
mongodb: {
host: string;
port: number;

View File

@ -26,17 +26,19 @@ export async function createImage(actor: IRemoteUser, value: any): Promise<IDriv
let file = await uploadFromUrl(image.url, actor, null, image.url, image.sensitive);
// URLが異なっている場合、同じ画像が以前に異なるURLで登録されていたということなので、
// URLを更新する
if (file.metadata.url !== image.url) {
file = await DriveFile.findOneAndUpdate({ _id: file._id }, {
$set: {
'metadata.url': image.url,
'metadata.uri': image.url
}
}, {
returnNewDocument: true
});
if (file.metadata.isRemote) {
// URLが異なっている場合、同じ画像が以前に異なるURLで登録されていたということなので、
// URLを更新する
if (file.metadata.url !== image.url) {
file = await DriveFile.findOneAndUpdate({ _id: file._id }, {
$set: {
'metadata.url': image.url,
'metadata.uri': image.url
}
}, {
returnNewDocument: true
});
}
}
return file;

View File

@ -41,7 +41,7 @@ app.use(compress({
// HSTS
// 6months (15552000sec)
if (config.url.startsWith('https')) {
if (config.url.startsWith('https') && !config.disableHsts) {
app.use(async (ctx, next) => {
ctx.set('strict-transport-security', 'max-age=15552000; preload');
await next();

View File

@ -37,10 +37,10 @@ async function save(path: string, name: string, type: string, hash: string, size
if (config.drive && config.drive.storage == 'minio') {
const minio = new Minio.Client(config.drive.config);
const keyDir = `${config.drive.prefix}/${uuid.v4()}`;
const key = `${keyDir}/${name}`;
const thumbnailKeyDir = `${config.drive.prefix}/${uuid.v4()}`;
const thumbnailKey = `${thumbnailKeyDir}/${name}.thumbnail.jpg`;
const [ext] = (name.match(/\.([a-zA-Z0-9_-]+)$/) || ['']);
const key = `${config.drive.prefix}/${uuid.v4()}${ext}`;
const thumbnailKey = `${config.drive.prefix}/${uuid.v4()}.jpg`;
const baseUrl = config.drive.baseUrl
|| `${ config.drive.config.useSSL ? 'https' : 'http' }://${ config.drive.config.endPoint }${ config.drive.config.port ? `:${config.drive.config.port}` : '' }/${ config.drive.bucket }`;
@ -64,8 +64,8 @@ async function save(path: string, name: string, type: string, hash: string, size
key: key,
thumbnailKey: thumbnailKey
},
url: `${ baseUrl }/${ keyDir }/${ encodeURIComponent(name) }`,
thumbnailUrl: thumbnail ? `${ baseUrl }/${ thumbnailKeyDir }/${ encodeURIComponent(name) }.thumbnail.jpg` : null
url: `${ baseUrl }/${ key }`,
thumbnailUrl: thumbnail ? `${ baseUrl }/${ thumbnailKey }` : null
});
const file = await DriveFile.insert({

View File

@ -0,0 +1,30 @@
import * as promiseLimit from 'promise-limit';
import DriveFile, { IDriveFile } from '../models/drive-file';
import del from '../services/drive/delete-file';
const limit = promiseLimit(16);
DriveFile.find({
'metadata._user.host': {
$ne: null
},
'metadata.deletedAt': { $exists: false }
}, {
fields: {
_id: true
}
}).then(async files => {
console.log(`there is ${files.length} files`);
await Promise.all(files.map(file => limit(() => job(file))));
console.log('ALL DONE');
});
async function job(file: IDriveFile): Promise<any> {
file = await DriveFile.findOne({ _id: file._id });
await del(file, true);
console.log('done', file._id);
}

View File

@ -85,16 +85,27 @@ const uploadFile = async (user: any): Promise<any> => {
describe('API', () => {
// Reset database each test
beforeEach(() => Promise.all([
db.get('users').drop(),
db.get('posts').drop(),
db.get('driveFiles.files').drop(),
db.get('driveFiles.chunks').drop(),
db.get('driveFolders').drop(),
db.get('apps').drop(),
db.get('accessTokens').drop(),
db.get('authSessions').drop()
]));
beforeEach(() => new Promise((res) => {
// APIがなにかレスポンスを返した後に、後処理を行う場合があり、
// レスポンスを受け取ってすぐデータベースをリセットすると
// その後処理と競合し(テスト自体は合格するものの)エラーがコンソールに出力され
// 見た目的に気持ち悪くなるので、後処理が終るのを待つために500msくらい待ってから
// データベースをリセットするようにする
setTimeout(async () => {
await Promise.all([
db.get('users').drop(),
db.get('posts').drop(),
db.get('driveFiles.files').drop(),
db.get('driveFiles.chunks').drop(),
db.get('driveFolders').drop(),
db.get('apps').drop(),
db.get('accessTokens').drop(),
db.get('authSessions').drop()
]);
res();
}, 500);
}));
describe('signup', () => {
it('不正なユーザー名でアカウントが作成できない', async(async () => {
@ -1114,4 +1125,76 @@ describe('API', () => {
expect(res).have.status(400);
}));
});
describe('messaging/messages/create', () => {
it('メッセージを送信できる', async(async () => {
const alice = await signup({ username: 'alice' });
const bob = await signup({ username: 'bob' });
const res = await request('/messaging/messages/create', {
userId: bob.id,
text: 'test'
}, alice);
expect(res).have.status(200);
expect(res.body).be.a('object');
expect(res.body).have.property('text').eql('test');
}));
it('自分自身にはメッセージを送信できない', async(async () => {
const alice = await signup({ username: 'alice' });
const res = await request('/messaging/messages/create', {
userId: alice.id,
text: 'Yo'
}, alice);
expect(res).have.status(400);
}));
it('存在しないユーザーにはメッセージを送信できない', async(async () => {
const alice = await signup({ username: 'alice' });
const res = await request('/messaging/messages/create', {
userId: '000000000000000000000000',
text: 'test'
}, alice);
expect(res).have.status(400);
}));
it('不正なユーザーIDで怒られる', async(async () => {
const alice = await signup({ username: 'alice' });
const res = await request('/messaging/messages/create', {
userId: 'foo',
text: 'test'
}, alice);
expect(res).have.status(400);
}));
it('テキストが無くて怒られる', async(async () => {
const alice = await signup({ username: 'alice' });
const bob = await signup({ username: 'bob' });
const res = await request('/messaging/messages/create', {
userId: bob.id
}, alice);
expect(res).have.status(400);
}));
it('文字数オーバーで怒られる', async(async () => {
const alice = await signup({ username: 'alice' });
const bob = await signup({ username: 'bob' });
const res = await request('/messaging/messages/create', {
userId: bob.id,
text: '!'.repeat(1001)
}, alice);
expect(res).have.status(400);
}));
});
});