archive.isの新しいサーバー

archive.isはサイトの著作権を無視しサイトを丸ごとコピーするのはご存じだと思います。
このブログも一部の画像はライセンス購入した物があるので、ライセンスに違反する為削除してほしい と要求を送ったけれど無視されました。

更にサイトのcanonical、description、keywords、OGP、Twitter情報を書き換えるため悪質です。
なのでうちは、archive.isサーバー群のIPアドレスからの接続をドロップしているのですが、どうも新しいサーバーを用意したみたいです。
(サーバー一覧等はarchive.is サーバーIPアドレス一覧前回の記事をご覧下さい。)

ちなみに、Googleにインデックスされたarchive.isのコピーサイトはGoogleへ著作権違反の報告をする事で検索インデックスから削除可能です。
私はこのブログの612ページ分を著作権違反で報告し削除してもらいました。

オリジナルサイトとarchive.isのコピーサイトがGoogleのインデックスに登録されてもarchive.isの順位が上がらないのは著作権違反の報告が多く、Webマスター側の権利が認められているからでしょうねー。
アーカイブ保存され困っているWebマスターさんはドンドン著作権違反でarchive.isを報告しましょう!
 
今回はそのarchive.isに新しいサーバーが増えたようで、見事にダミーサイトがアーカイブされちゃいました。
サーバーはスパム業者を排除しない事で有名なLinode LLCのサーバー。
確認したIPアドレスは139.162.218.90です。
RIRへの照会情報は

% This is the RIPE Database query service.
% The objects are in RPSL format.
%
% The RIPE Database is subject to Terms and Conditions.
% See http://www.ripe.net/db/support/db-terms-conditions.pdf
% Note: this output has been filtered.
% To receive output for a database update, use the "-B" flag.
% Information related to '139.162.0.0 - 139.162.255.255'
% Abuse contact for '139.162.0.0 - 139.162.255.255' is 'abuse@linode.com'
inetnum: 139.162.0.0 - 139.162.255.255
netname: EU-LINODE-20141229
descr: 139.162.0.0/16
org: ORG-LL198-RIPE
country: US
admin-c: TA2589-RIPE
tech-c: TA2589-RIPE
tech-c: LA538-RIPE
status: LEGACY
remarks: For information on "status:" attribute read https://www.ripe.net/data-tools/db/faq/faq-status-values-legacy-resources
remarks: Please send abuse reports to abuse@linode.com
mnt-by: linode-leg-mnt
created: 2004-02-02T16:20:09Z
last-modified: 2015-05-05T01:52:02Z
source: RIPE

organisation: ORG-LL198-RIPE
org-name: Linode, LLC
org-type: OTHER
address: 329 E. Jimmie Leeds Road, Suite A, Galloway, NJ 08205
abuse-c: AR31889-RIPE
abuse-mailbox: abuse@linode.com
mnt-ref: linode-leg-mnt
mnt-by: linode-leg-mnt
created: 2015-04-20T03:09:43Z
last-modified: 2015-04-20T03:18:36Z
source: RIPE # Filtered

person: Linode Abuse Support
address: 329 E. Jimmie Leeds Road, Suite A, Galloway, NJ 08205, USA
phone: +16093807100
abuse-mailbox: abuse@linode.com
nic-hdl: LA538-RIPE
mnt-by: Linode-mnt
created: 2009-11-11T15:16:50Z
last-modified: 2015-08-13T19:55:05Z
source: RIPE

person: Thomas Asaro
address: 329 E. Jimmie Leeds Road, Suite A, Galloway, NJ 08205, USA
phone: +16093807504
nic-hdl: TA2589-RIPE
mnt-by: Linode-mnt
created: 2009-11-02T17:17:56Z
last-modified: 2014-11-20T18:51:15Z
source: RIPE

% Information related to '139.162.192.0/19AS15830'
route: 139.162.192.0/19
descr: LINODE-UK
origin: AS15830
mnt-by: LINODE-LEG-MNT
created: 2015-06-17T20:45:47Z
last-modified: 2015-06-17T20:45:47Z
source: RIPE
% This query was served by the RIPE Database Query Service version 1.87.4 (DB-1)

うん紛うことなくLinode LLCのサーバー。
逆引きホスト名もli1381-90.members.linode.comなので間違いなし。

いやー、スパムの苗床Linodeを選ぶとは流石archive.isさん!
アビューズ報告してもレンタル先から処分されないんだから絶好のサーバーですよねー
archive.is サーバーIPアドレス一覧ページは既に反映済みです。

スパムメールとかのサイトを弄って遊ぶみたいに、archive.isでも遊べないかな・・・?と思っていたら、ちょっと面白いことを思いついたので実行してみました。
続きを読む »

新しいIP範囲からのスパム

第1オクテットが103のスパムを片っ端からブロックしてたら、来るスパムが減って安心していました。
しかし、今日新しい範囲からスパムらしく短期間に山ほどメールが来ました。

文面の特徴が一致しているので同じ業者だとわかります。
とりあえず、文面はこんな感じ。

第1オクテットが103のスパム

差出人: ◆1700万円をすぐ受け取ってください◆即送金可能◆ <df21bd3@fh1jzkmb3b.com>
件名: Ш至急1700万円を受け取ってもらえませんか?急に変な事を言ってごめんなさい、でも騙したりするつもりで送っている訳じゃないので、とりあえず話しを聞いてもらえませんか? 添付写真
--------------------

◆1700万円をすぐ受け取ってください◆即送金可能◆様よりメールあり!
http://fh1jzkmb3b.com/...

退会なども上記より

 
第1オクテットが59のスパム

差出人: 専属送/金担当者:相川 絵里 <fth51rfcv@e275bj363e.com>
件名: £10,0/0円.【1度のご購,入】お一人様γあたり『960.0万,円』ご送/金のご案/内γで御.座/いますγ!専属送,金担当者,:相川 絵里
--------------------

専属送/金担当者:相川 絵里,様.よ,りメ,ッ/セ,ー/ジあり♪
http://e275bj363e.com/...

退.会なども上/記より

 
今回の送信元IPアドレスをRIRへ照会すると・・・

% [whois.apnic.net]
% Whois data copyright terms http://www.apnic.net/db/dbcopyright.html
% Information related to '59.153.205.0 - 59.153.205.255'
inetnum: 59.153.205.0 - 59.153.205.255
netname: ACCESSNETLLC-JP
descr: ACCESS-NET LLC
descr: 1403 Win Aoyama, 2-2-15 Minami-Aoyama
country: JP
admin-c: ALA2-AP
tech-c: ALA2-AP
status: ALLOCATED NON-PORTABLE
mnt-by: MAINT-ACCESSNETLLC-JP
mnt-irt: IRT-ACCESSNETLLC-JP
changed: info@access-n.net 20151105
source: APNIC
irt: IRT-ACCESSNETLLC-JP
address: 1403 Win Aoyama, 2-2-15 Minami-Aoyama, Minato-Ku Tokyo 107-0062
e-mail: info@access-n.net
abuse-mailbox: info@access-n.net
admin-c: ALA2-AP
tech-c: ALA2-AP
auth: # Filtered
mnt-by: MAINT-ACCESSNETLLC-JP
changed: hm-changed@apnic.net 20130718
source: APNIC
role: ACCESS-NET LLC administrator
address: 1403 Win Aoyama, 2-2-15 Minami-Aoyama, Minato-Ku Tokyo 107-0062
country: JP
phone: +81368691858
fax-no: +81368691858
e-mail: info@access-n.net
admin-c: ALA2-AP
tech-c: ALA2-AP
nic-hdl: ALA2-AP
mnt-by: MAINT-ACCESSNETLLC-JP
changed: hm-changed@apnic.net 20130718
source: APNIC
% This query was served by the APNIC Whois Service version 1.69.1-APNICv1r0 (UNDEFINED)

うん、やっぱり送信元はいつものヤクザスパムでした。
これからは103に加え59も警戒する必要があるかもしれません。

いつもの、スパム送信元リストには追加済みです。

ちなみに、Webサイトは脆弱性がモリモリあるのでTor等で匿名化して相手サーバーを弄って遊んでみるのがオススメです。

スタイルシートをLESSにかえてみた。

サーバー側のCSS/JavaScriptをまとめて最適化+難読化するシステムを作り直して、The Dynamic Stylesheet language (LESS)に対応させました。
LESSのコンパイルにはlessphpライブラリを使用。

LESSってナニー?って感じですが、LESSは主に開発者側がCSSを使いやすく、メンテナンスが容易にするためのCSSプリプロセッサなんです。
CSSでネックだった変数、関数、演算が使えるので、開発者からすればCSSの視認性の上昇やコードの短縮ができます。

なのでWebを閲覧するユーザー側からしたら特にメリットはなく、クライアント側コンパイラを使う場合はページ表示速度低下があるのでデメリットしかありません。
しかし、コンパイルをサーバー側でやっておくとユーザー側のストレスはCSSと全く同じ。

これはメンテナンスをし易くするために使ってみねば!という事で・・・
とりあえず、よく使うアンカーエレメントの訪問済みリンクやマウスオーバーの色を指定するやつはこうなります。

CSS

a:link {
    color: #0d85cc;
    text-decoration: none;
}
 
a:visited {
    color: #0d85cc;
    text-decoration: none;;
}
 
a:active, a:hover {
    color: #12a7ff;
}
LESS

a {
    &:link {
        color: #0d85cc;
        text-decoration: none;
    }
 
    &:visited {
        color: #0d85cc;
        text-decoration: none;
    }
 
    &:active, &:hover {
        color: #12a7ff;
    }
}

 
少しややこしいCSSのサンプル。
このブログのフォームにも使っているCSSで、inputやtextareaのマウスオーバーやフォーカスを当てた時に縁が変化するやつはこうなる。
CSS

input, textarea, select {
    color: #666;
    background: #fff;
    font-size: 12px;
    line-height: 18px;
}
 
input:not([readonly]):not([disabled]):hover, 
textarea:not([readonly]):not([disabled]):hover, 
select:not([readonly]):not([disabled]):hover {
    background: #f6f6f6;
}
 
input:not([readonly]):not([disabled]):focus, 
textarea:not([readonly]):not([disabled]):focus, 
select:not([readonly]):not([disabled]):focus {
    transition-duration: 0.3s;
 
    background: #fff;
    border-color: #75b9f0;
    outline: 0px none;
    box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset, 0px 0px 8px #75b9f0;
}

LESS

input, textarea, select {
    color: #666;
    background: #fff;
    font-size: 12px;
    line-height: 18px;
 
    &:not([readonly]):not([disabled]):hover {
        background: #f6f6f6;
    }
 
    &:not([readonly]):not([disabled]):focus {
        transition-duration: 0.3s;
 
        background: #fff;
        border-color: #75b9f0;
        outline: 0px none;
        box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset, 0px 0px 8px #75b9f0;
    }
}

ロケーション疑似クラスを使ってたり複数指定しているCSSは格段に見やすく、そしてシンプルになりますねー!
 
うちのブログのCSSもLESSにかえてみたら、CSSで62.5Kb、LESSで37.7Kbのファイルサイズに。
LESSをコンパイルすれば同じぐらいのサイズになったので、書き方の違いがあるだけでCSSとLESSをコンパイルした物はかわらなかった。
CSSとLESS
画像はCSSをLESSに作り直しをしているところだけれど、視認性が高くファイルサイズが小さくなってるのがよくわかりますねw

本当にこれは使いやすくて良い感じ(`・ω・)b

WordPressのパスワード保護している記事のtitleも変更する

今現在、WordPressでパスワード保護された記事の本文やコメントは非表示になりますが、titleエレメントやRSSなんかは非表示になりません。
今回は非推奨になったwp_titleとWordPress 4.4から登場したadd_theme_support('title-tag')を有効化したテーマ等で使うwp_get_document_title()でも使える方法でいきます。

序でに「非公開:」や「保護中:」って文字も削除・変更しちゃいますー。

まずは完成したWordPressのプラグインコード。

<?php
/*
Plugin Name: Change Password POST Title
Plugin URI: http://blog.wolfs.jp/20160513-3616/
Description: パスワードで保護された記事のタイトルを変更します。
Version: 1.0.0
Author: Kerberos
Author URI: http://blog.wolfs.jp/
*/
 
class changePasswordPostTitle {
    private $plugin_dir = ABSPATH.'/wp-content/plugins/change_password_post_title/feed/';
    private $post_password_title = '[パスワードで保護された記事]';
 
    public function __construct() {
        add_filter('the_title', array($this, 'the_title'), 10, 2);
        add_filter('pre_get_document_title', array($this, 'pre_get_document_title'));
        add_filter('protected_title_format', array($this, 'protected_title_format'));
 
        add_filter('aioseop_title_single', array($this, 'aioseop_title'));
        add_filter('aioseop_title_page', array($this, 'aioseop_title'));
 
        remove_action('do_feed_rss2', 'do_feed_rss2');
        remove_action('do_feed_atom', 'do_feed_atom');
        add_action('do_feed_rss2', array($this, 'do_feed_rss2'), 10, 1);
        add_action('do_feed_atom', array($this, 'do_feed_atom'), 10, 1);
    }
 
 
    public function the_title($title = '', $currentID = 0) {
        global $post;
 
        if ($currentID !== 0) {
            if (post_password_required($currentID) === true) {
                if ($post->ID == $currentID && is_admin() === false) {
                    return $this->post_password_title;
                }
            }
 
            return $this->remove_title_prefix($title);
        }
 
        return $title;
    }
 
    public function pre_get_document_title($title) {
        if (is_single() === true || is_page() === true) {
            if (post_password_required($post->ID) === true) {
                return $this->post_password_title;
            }
 
            return $this->remove_title_prefix($title);
        }
 
        return $title;
    }
 
    public function protected_title_format($title) {
        global $post;
 
        if (post_password_required($post->ID) === false) {
            return '&#x1F512; %s';
        }
 
        return $this->post_password_title;
    }
 
    public function aioseop_title($title) {
        global $post;
 
        if (post_password_required($post->ID) === true) {
            return $this->post_password_title;
        }
 
        return $title;
    }
 
    private function remove_title_prefix($title) {
        $search[0] = '/^' . str_replace('%s', '(.*)', preg_quote(__('Protected: %s'), '/' )) . '$/';
        $search[1] = '/^' . str_replace('%s', '(.*)', preg_quote(__('Private: %s'), '/' )) . '$/';
 
        return preg_replace($search, '$1', $title);
    }
 
 
    public function do_feed_rss2($for_comments) {
        if ($for_comments) {
            load_template($this->plugin_dir.'feed-rss2-comments.php');
        }
    }
 
    public function do_feed_atom($for_comments) {
        if ($for_comments) {
            load_template($this->plugin_dir.'feed-atom-comments.php');
        }
    }
}
 
new changePasswordPostTitle();
?>

フィルターのフック名と関数は同じ名前にしてあるのでわかると思うので、その辺は略しますw
このプラグインでパスワード保護ページはこうなります:サンプルページ
続きを読む »

e621.netで画像保存を楽にする

e621.netってケモノ絵や話題を投稿するサイトがあるんです。
ここは健全な絵もあるけれどR18な絵も多数ある所。
ケモノが好きな人は見てて飽きない所ですねw

ぼーっと見ていたら、とあるアーティストさんの過去絵が沢山あったので、ガンガン保存していたら保存ダイアログを出すのがメンドウになってきましたw
なので自動化・・はダルイしイラナイ画像も拾うから画像をダブルクリックするだけで保存ダイアログが出るようにuserChromeを作ってみました。

e621net-supporter.uc.js

// ==UserScript==
// @name           e621.net: 画像保存サポーター
// @namespace      http://blog.wolfs.jp/
// @description
// ==/UserScript==
 
var e621netSupporterObj = {
    targetHost: 'e621.net',
    targetPage: 'e621.net/post/show/',
 
    isTargetPage: false,
    lastTime: 0,
 
    clickID: {
        left: 0,
        right: 2,
        center: 1
    },
 
    init: function() {
        gBrowser.mPanelContainer.addEventListener("dblclick", this, true);
    },
 
    handleEvent: function(event) {
        if (gBrowser.currentURI.asciiSpec.indexOf(this.targetPage) != -1) {
            event = new XPCNativeWrapper(event);
            if (event.target instanceof HTMLImageElement) {
                if (event.target.id == 'image') {
                    event.preventDefault();
 
                    if (new Date().getTime() - this.lastTime > 5000) {
                        this.lastTime = new Date().getTime();
 
                        var img = this.getImage(event.target.src);
                        if (img != null) {
                            this.saveImage(img, this.getFileName(event.target.src));
                        }
                        img = null;
                    }
                }
            }
        }
    },
 
    getFileName: function(url) {
        return url.match(".+/(.+?)([\?#;].*)?$")[1];
    },
 
    getImage: function(url) {
        var request = new XMLHttpRequest();
        request.open('GET', url, false);
        request.overrideMimeType('text/plain; charset=x-user-defined');
        request.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
        request.send(null);
 
        if (request.status == 200) {
            return request.responseText;
        }
 
        request = null;
        return null;
    },
 
    saveImage: function(imageData, requestFileName) {
        var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
        fp.init(window, 'Select a file', Components.interfaces.nsIFilePicker.modeSave);
        //fp.appendFilters(Components.interfaces.nsIFilePicker.filterImages);
        //fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
        fp.appendFilter('JPEG Image', '*.jpg');
        fp.appendFilter('PNG Image', '*.png');
        fp.appendFilter('GIF Image', '*.gif');
        fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
 
        fp.defaultString = requestFileName;
        switch (requestFileName.split('.')[1]) {
            case 'jpg':
                fp.defaultExtension = 'jpg';
                fp.filterIndex = 0;
                break;
            case 'png':
                fp.defaultExtension = 'png';
                fp.filterIndex = 1;
                break;
            case 'gif':
                fp.defaultExtension = 'gif';
                fp.filterIndex = 2;
                break;
            default:
                fp.filterIndex = 3;
        }
 
        switch (fp.show()) {
            case Components.interfaces.nsIFilePicker.returnOK:
            case Components.interfaces.nsIFilePicker.returnReplace:
                var outStream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
                outStream.init(fp.file, 0x02 | 0x08 | 0x20, 0664, 0);
                outStream.write(imageData, imageData.length);
                if (outStream instanceof Components.interfaces.nsISafeOutputStream) {
                    outStream.finish();
                } else {
                    outStream.close();
                }
                outStream = null;
                break;
            case Components.interfaces.nsIFilePicker.returnCancel:
                break;
        }
    }
};
 
e621netSupporterObj.init();

本当はグリモンとかでサクッと実装したかったけれど、保存ダイアログをだすfilepickerやfile-output-streamなんかは呼び出せないので、権限があるuserChromeで実装。

内容は簡単。
 1.ダブルクリックされたらページのURLがe621.net/post/show/かどうか比較。
 2.対象のページだった場合はクリック先のエレメントがHTMLImageElementかつIDがimageか確認。
 3.imageだった場合はXMLHttpRequestで画像のバイナリを獲得。
   これは既に表示されている画像のキャッシュが効くのでいいb
 4.画像を正常に読み込めたら保存ダイアログを呼び出して保存先やファイル名を決定。
って感じ。

userChromeだけれど、内容はFirefox系のAPIに依存しているのでFirefox系ブラウザ専用です。